/*++ Copyright (c) 1988-1999 Microsoft Corporation Module Name: cinfo.c Abstract: Information command support --*/ #include "cmd.h" #define TYPEBUFSIZE 80 #define TYPEREADSIZE 512 extern UINT CurrentCP; extern unsigned DosErr ; extern unsigned tywild; /* @@5@J1 type wild cards */ extern TCHAR CurDrvDir[] ; extern TCHAR VolSrch[] ; /* M006 - Search string for Volume ID */ extern TCHAR AppendStr[] ; extern TCHAR Fmt26[], Fmt25[]; extern unsigned LastRetCode; extern BOOL CtrlCSeen; struct FSVol { unsigned long SerNum ; /* Volume serial number */ TCHAR len ; /* Volume name len (excludes \0) */ TCHAR name[257] ; /* Volume name asciz */ }; int ZScanA(BOOL flag, PCHAR buf, PULONG buflen, PULONG skip); /**************** START OF SPECIFICATIONS ***********************/ /* */ /* SUBROUTINE NAME: eDirectory */ /* */ /* DESCRIPTIVE NAME: Begin execution of the DIR command */ /* */ /* FUNCTION: To list out the files on a disk. eDirectory will */ /* be called whenever the user enters the DIR command */ /* on the command line. DIR will continue if it */ /* encounters an invalid argument. */ /* */ /* NOTES: */ /* */ /* ENTRY POINT: eDirectory */ /* LINKAGE: Near */ /* */ /* INPUT: n - the parse tree node containing the DIR command */ /* */ /* EXIT-NORMAL: return SUCCESS if no errors occur */ /* */ /* EXIT-ERROR: return FAILURE otherwise */ /* */ /* EFFECTS: None. */ /* */ /* INTERNAL REFERENCES: */ /* ROUTINES: */ /* Dir - lists out the files in a directory */ /* */ /* EXTERNAL REFERENCES: */ /* ROUTINES: */ /* */ /**************** END OF SPECIFICATIONS *************************/ int eDirectory(n) struct cmdnode *n ; { return(LastRetCode = Dir(n->argptr)) ; } /*** eType - begin the execution of a Type command * * Purpose: * To type the contents of an arbitrary number of files. * * int eType(struct cmdnode *n) * * Args: * n - the parse tree note containing the type command * * Returns: * SUCCESS if all of the files were successfully typed. * FAILURE otherwise. * */ int eType(n) struct cmdnode *n ; { // // Removed LTA_NOMATCH from flags. This caused a *.xxx to call the TyWork // function which would think that *.xxx is a file and try to open it. // return(LastRetCode = LoopThroughArgs(n->argptr, TyWork, LTA_EXPAND | LTA_CONT | LTA_NOMATCH)) ; } /*** TyWork - display a file * * Purpose: * Write the contents of the file specified in fspec to stdout. * Output ends when all of fspec has been written or a ^Z is found in * fspec. * * int TyWork(TCHAR *fspec) * * Args: * fspec - the name of the file to write out * * Returns: * SUCCESS if the file was written. * FAILURE otherwise, such as inability to allocate a temporary buffer */ int TyWork(TCHAR *fspec) { TCHAR fspec_temp[MAX_PATH]; TCHAR TypeBufW[TYPEREADSIZE*3]; CHAR TypeBuf[TYPEREADSIZE+1]; ULONG result; BOOL flag; const TCHAR *bptr; ULONG fDevice = 0; ULONG maxbytes = 0xFFFFFFFF ; // max file size ULONG bytestoctlz ; // Number of bytes read ULONG bytesread ; // Number of bytes read ULONG byteswrit ; // Number of bytes read ULONG brcopy ; // Bytes to copy CRTHANDLE fh ; // File handle int first_read; // first read on file for wild int TypeBufSize; int rc; LONG bWrite; CHAR *pType; #ifdef UNICODE WCHAR wc; BOOL fUnicode=FALSE; #endif // UNICODE TypeBufSize = TYPEREADSIZE; first_read = TRUE; /* set flag to test for wilds @@5@J1 */ DEBUG((ICGRP, TYLVL, "TYWORK: fspec = `%ws'", fspec)) ; if ((fh = Copen(fspec, O_RDONLY)) == BADHANDLE) { bptr = MyGetEnvVarPtr(AppendStr); if ( bptr != NULL && SearchPath( bptr, (TCHAR *)fspec, NULL, (unsigned)MAX_PATH, (TCHAR *)fspec_temp, NULL ) != 0) { fh = Copen(fspec_temp, O_RDONLY); } } if ( fh == BADHANDLE ) { if (DosErr == ERROR_INVALID_NAME) { DosErr = ERROR_FILE_NOT_FOUND; } PrtErr(DosErr) ; rc = FAILURE; goto TypeExit; } /************************************************************/ /* M004 - Added code to get max file size if not device */ /************************************************************/ bptr = (TCHAR*)TypeBuf; /* Copy of original pointer*/ if (!FileIsDevice(fh)) { maxbytes = GetFileSize(CRTTONT(fh), NULL) ; /* Get file size */ SetFilePointer(CRTTONT(fh), 0L, NULL, FILE_BEGIN) ; /* Return pointer*/ fDevice = 1 ; /* Set no device flag */ DEBUG((ICGRP,TYLVL,"TYWORK: Is file, size=%d", maxbytes)) ; } do { if (CtrlCSeen) { Cclose(fh) ; rc = FAILURE; goto TypeExit; } if (!ReadFile(CRTTONT(fh), TypeBuf, TypeBufSize, (LPDWORD)&bytesread, NULL)) { DosErr = GetLastError(); PutStdErr(DosErr, NOARGS); break; } if (bytesread == 0) { break; } #ifdef UNICODE if (first_read) { fUnicode = *(LPWSTR)TypeBuf == BYTE_ORDER_MARK; if (fUnicode) { bytesread -= sizeof( TCHAR ); MoveMemory( TypeBuf, TypeBuf + sizeof( TCHAR ), bytesread ); } } #endif // UNICODE bytestoctlz = bytesread; #ifdef UNICODE if (fUnicode) { if (first_read) { DEBUG((ICGRP, TYLVL, "TYWORK: file is unicode")) ; } brcopy = bytesread / sizeof(TCHAR); } else #endif // UNICODE if (FileIsConsole(STDOUT) #ifdef UNICODE || fOutputUnicode #endif // UNICODE ) { PCHAR pch = TypeBuf; brcopy = bytesread; while (brcopy > 0) { if (is_dbcsleadchar(*pch)) { pch++; if (--brcopy == 0) { if (!ReadFile(CRTTONT(fh), pch, 1, &brcopy, NULL)) { DosErr = GetLastError(); PutStdErr(DosErr, NOARGS); Cclose(fh) ; rc = SUCCESS; goto TypeExit; } bytesread++; bytestoctlz = bytesread; break; } } pch++; brcopy--; } result = 0; flag = ZScanA(TRUE, (PCHAR)TypeBuf, &bytestoctlz, &result); DEBUG((ICGRP, TYLVL, "TYWORK: converting %d bytes to unicode", flag?bytesread:bytestoctlz)) ; if ( (!flag) && (bytestoctlz == 0) ) break; brcopy = MultiByteToWideChar(CurrentCP, 0, (LPCSTR)TypeBuf, flag?bytesread:bytestoctlz, (LPWSTR)TypeBufW, TypeBufSize*2); if (brcopy == 0) { DEBUG((ICGRP, TYLVL, "TYWORK: Error converting to Unicode: %d", GetLastError())) ; brcopy = TypeBufSize*2; } bptr = TypeBufW; } else { brcopy = bytesread; } if (first_read) { if (tywild) PutStdErr(MSG_TYPE_FILENAME, ONEARG, fspec); first_read = FALSE; } DEBUG((ICGRP, TYLVL, "TYWORK: bytesread = %d, brcopy = %d", bytesread, brcopy)) ; bWrite = brcopy; pType = (CHAR *)bptr; while ( bWrite > 0 ) { ULONG bToWrite = min( TYPEBUFSIZE, bWrite ); if ( bToWrite == 0 ) { break; } if (CtrlCSeen) { Cclose(fh) ; rc = FAILURE; goto TypeExit; } if (FileIsConsole(STDOUT)) { DEBUG((ICGRP, TYLVL, "TYWORK: Writing to console")) ; flag = WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pType, bToWrite, &byteswrit, NULL); if (flag == 0 || byteswrit != bToWrite) { goto try_again; } bWrite -= byteswrit; byteswrit *= sizeof(TCHAR); pType += byteswrit; #ifdef UNICODE } else if (fOutputUnicode || fUnicode) { if ( fUnicode ) { wc = *((TCHAR*)pType + bToWrite); *((TCHAR*)pType + bToWrite) = UNICODE_NULL; } DEBUG((ICGRP, TYLVL, "TYWORK: Writing unicode text to file")) ; flag = MyWriteFile( STDOUT, /* device */ pType, /* bytes */ bToWrite * sizeof(TCHAR), /* bytes to write */ &byteswrit); /* bytes actually written */ if ( fUnicode ) { *((TCHAR*)pType + bToWrite) = wc; } bWrite -= byteswrit/sizeof(TCHAR); pType += byteswrit; #endif // UNICODE } else { try_again: DEBUG((ICGRP, TYLVL, "TYWORK: Writing dbcs text to file")) ; flag = WriteFile(CRTTONT(STDOUT), pType, bToWrite, &byteswrit, NULL); bWrite -= byteswrit; pType += byteswrit; byteswrit *= sizeof(TCHAR); } DEBUG((ICGRP, TYLVL, "TYWORK: flag = %d, byteswrit = %d", flag, byteswrit)) ; if (flag == 0 || byteswrit != bToWrite*sizeof(TCHAR)) { DosErr = GetLastError(); if (!DosErr) { DosErr = ERROR_DISK_FULL ; } if (FileIsDevice(STDOUT)) { PutStdErr(ERROR_WRITE_FAULT, NOARGS); } else { if (FileIsPipe(STDOUT)) { PutStdErr(MSG_CMD_INVAL_PIPE, NOARGS); } else { PrtErr(DosErr); } Cclose(fh); rc = FAILURE; goto TypeExit; } } } if (fDevice) { /* If not device */ /* Get new position ptr */ fDevice = SetFilePointer(CRTTONT(fh), 0, NULL, FILE_CURRENT); } /*************************************************/ /* Added check below for current file position */ /* at original EOF */ /*************************************************/ } while((bytesread == bytestoctlz) && (maxbytes > fDevice)); Cclose(fh) ; rc = SUCCESS; TypeExit: return(rc) ; } /*** eVersion - execute the Version command * * Purpose: * To print DOS version information. * * int eVersion(struct cmdnode *n) * * Args: * n - the parse tree node containing the version command. N will be NULL * if eVersion was called from PrintPrompt(). * * Returns: * SUCCESS always. * */ int eVersion( struct cmdnode *n ) { TCHAR VersionFormat[32]; GetVersionString( VersionFormat, sizeof( VersionFormat ) / sizeof( VersionFormat[0] )); if (n) cmd_printf( CrLf ); PutStdOut( MSG_MS_DOS_VERSION, ONEARG, VersionFormat ); if (n) cmd_printf( CrLf ); return(LastRetCode = SUCCESS) ; } /**************** START OF SPECIFICATIONS ***********************/ /* */ /* SUBROUTINE NAME: eVolume */ /* */ /* DESCRIPTIVE NAME: Begin execution of the VOL command */ /* */ /* FUNCTION: eVolume will print out the volume label and serial */ /* number for an arbitrary number of drives, and will */ /* continue if it encounters an invalid argument. */ /* This routine is called when the user enters VOL */ /* on the command line. */ /* */ /* NOTES: */ /* */ /* ENTRY POINT: eVolume */ /* LINKAGE: Near */ /* */ /* INPUT: n - a parse tree node containing the VOL command */ /* */ /* EXIT-NORMAL: returns SUCCESS if the command was well formed, */ /* and was executed successfully. */ /* */ /* EXIT-ERROR: returns FAILURE otherwise. */ /* */ /* EFFECTS: None. */ /* */ /* INTERNAL REFERENCES: */ /* ROUTINES: */ /* LoopThroughArgs - breaks up command line, calls VolWork */ /* */ /* EXTERNAL REFERENCES: */ /* ROUTINES: */ /* */ /**************** END OF SPECIFICATIONS *************************/ int eVolume(n) struct cmdnode *n ; { return(LastRetCode = LoopThroughArgs(n->argptr, VolWork, LTA_CONT|LTA_NULLOK)) ; } /**************** START OF SPECIFICATIONS ***********************/ /* */ /* SUBROUTINE NAME: VolWork */ /* */ /* DESCRIPTIVE NAME: Display the volume ID of a drive */ /* */ /* FUNCTION: VolWork will print the volume label and serial */ /* number of a specific drive. */ /* */ /* NOTES: */ /* */ /* ENTRY POINT: VolWork */ /* LINKAGE: Near */ /* */ /* INPUT: drvspec - a pointer to a character specifying the */ /* drive to print the information for. If the */ /* character is null, the information for the */ /* current drive is displayed. */ /* */ /* EXIT-NORMAL: returns SUCCESS if the command was executed */ /* successfully */ /* */ /* EXIT-ERROR: returns FAILURE otherwise */ /* */ /* EFFECTS: None. */ /* */ /* INTERNAL REFERENCES: */ /* ROUTINES: */ /* PutStdOut - Writes output to standard out */ /* PutStdErr - Writes output to standard error */ /* */ /* EXTERNAL REFERENCES: */ /* ROUTINES: */ /* DOSQFSINFO */ /* */ /**************** END OF SPECIFICATIONS *************************/ int VolWork(drvspec) TCHAR *drvspec ; { struct FSVol vol ; unsigned DNum ; TCHAR c ; TCHAR VolumeRoot[] = TEXT(" :\\"); DWORD Vsn[2]; BOOL b; DEBUG((ICGRP, VOLVL, "VOLWORK: drvspec = `%ws'", drvspec)) ; if (*drvspec == NULLC) { DNum = 0 ; c = (TCHAR) _totupper(CurDrvDir[0]) ; } else if ((mystrlen(drvspec) == 2) && *(drvspec+1) == COLON && _istalpha(*drvspec)) { c = (TCHAR) _totupper(*drvspec) ; DNum = (unsigned)(c - 0x40) ; } else { cmd_printf(CrLf); PutStdErr(ERROR_INVALID_DRIVE, NOARGS) ; /* M013 */ return(FAILURE) ; } ; VolumeRoot[0] = c; b = GetVolumeInformation(VolumeRoot,vol.name,sizeof(vol.name),Vsn,NULL,NULL,NULL,0); if (!b) { DEBUG((ICGRP, VOLVL, "VOLWORK: GetVolumeInformation ret'd %d", GetLastError())) ; cmd_printf(CrLf); if (GetLastError() == ERROR_NOT_READY) PutStdErr(ERROR_NOT_READY, NOARGS) ; else PutStdErr(GetLastError(), NOARGS) ; /* @@5a */ return(FAILURE) ; } else { if (b && vol.name[0]) { /* M013 */ PutStdOut(MSG_DR_VOL_LABEL, TWOARGS, argstr1( TEXT("%c"), (ULONG_PTR)c), vol.name ) ; } else { /* M013 */ PutStdOut(MSG_HAS_NO_LABEL, ONEARG, argstr1( TEXT("%c"), (ULONG_PTR)c)) ; } /* @@5 */ if (b) { // FIX, FIX TCHAR Buffer[128]; _sntprintf(Buffer, 128, Fmt26, (Vsn[0] & 0xffff0000)>>16, (Vsn[0] & 0xffff)); PutStdOut(MSG_DR_VOL_SERIAL, ONEARG, Buffer ); /* @@5 */ } } ; return(SUCCESS) ; } /**************************************************************** * * ZScanA - scan data in an arbitrary segment for ^Zs * * Purpose: * If flag is on, scan buffer for a ^Z. If it is found, update the * buffer length and return 0. Otherwise return -1. * Double byte characters are taken into account. * * int ZScanA(int flag, long buffer, unsigned *buflenptr, int *skip_first) * * Args: * flag - nonzero if any scanning is to be done * buffer - a long pointer to the buffer to use * buflenptr - ptr to the length of buffer * skip_first - ptr to an integer. The initial value of *skip_first * must be 0 on the first call when scanning a file. There * after, the caller leaves *skip_first alone. ZScan uses * the variable to remember if the first byte of the next * buffer is going to be the second have of a double * byte character. * * Returns: * See above. * * Notes: * This routine will need to be modified once the MMU code is in the DOS. * macro is defined in cmd.h. * * * ZScanA * if (flag) then * buffer = buffer + *skip_first * dbcs_flag = 0 * count = *buflenptr - *skip_first * use rep scanb to find first ^Z in buffer * if (no ^z was found) * goto FZSNoZ * do { * count++; * buffer--; * } until (*buffer < 0x80 || count = *buflenptr); * while (--count > 0) loop * if (dbcs_flag == 0) then * if (*buffer == ^Z) then * *buflenptr = count * return(0) * else if (*buffer is a dbcs_lead_char) then * dbcs_flag = 1 * endif * endif * else * dbcs_flag = 0 * buffer = buffer + 1 * count = count - 1 * end loop * *skip_first = dbcs_flag * endif *FZSNoZ: * return(-1) *---- ****************************************************************/ int ZScanA(BOOL flag, PCHAR buf, PULONG buflen, PULONG skip) { PCHAR pbuf = buf, bufend; CHAR c0; if ( flag ) { pbuf += *skip; bufend = buf + *buflen - *skip; while (pbuf < bufend) { if (is_dbcsleadchar(c0=*pbuf)) pbuf++; if (c0 == CTRLZ) break; pbuf++; } if (c0 == CTRLZ) { // *buflen = pbuf+1 - buf; *buflen = (ULONG)(pbuf - buf); *skip = 0; return(0); } else { *skip = (ULONG)(pbuf - bufend); } } return(-1); }