1 /* 2 * TYPE.C - type internal command. 3 * 4 * History: 5 * 6 * 07/08/1998 (John P. Price) 7 * started. 8 * 9 * 07/12/98 (Rob Lake) 10 * Changed error messages 11 * 12 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>) 13 * added config.h include 14 * 15 * 07-Jan-1999 (Eric Kohl) 16 * Added support for quoted arguments (type "test file.dat"). 17 * Cleaned up. 18 * 19 * 19-Jan-1999 (Eric Kohl) 20 * Unicode and redirection ready! 21 * 22 * 19-Jan-1999 (Paolo Pantaleo <paolopan@freemail.it>) 23 * Added multiple file support (copied from y.c) 24 * 25 * 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>) 26 * Remove all hardcoded strings in En.rc 27 */ 28 29 #include "precomp.h" 30 31 #ifdef INCLUDE_CMD_TYPE 32 33 static BOOL 34 FileGetString( 35 IN HANDLE hFile, 36 OUT LPTSTR lpBuffer, 37 IN LONG nBufferLength) 38 { 39 PCHAR pString; 40 DWORD dwRead; 41 LONG len = 0; 42 43 #ifdef _UNICODE 44 pString = cmd_alloc(nBufferLength); 45 #else 46 pString = lpBuffer; 47 #endif 48 49 if (ReadFile(hFile, pString, nBufferLength - 1, &dwRead, NULL)) 50 { 51 /* Break at new line*/ 52 PCHAR end = memchr(pString, '\n', dwRead); 53 len = dwRead; 54 if (end) 55 { 56 len = (LONG)(end - pString) + 1; 57 SetFilePointer(hFile, len - dwRead, NULL, FILE_CURRENT); 58 } 59 } 60 61 if (!len) 62 { 63 #ifdef _UNICODE 64 cmd_free(pString); 65 #endif 66 return FALSE; 67 } 68 69 pString[len++] = '\0'; 70 #ifdef _UNICODE 71 MultiByteToWideChar(OutputCodePage, 0, pString, -1, lpBuffer, len); 72 cmd_free(pString); 73 #endif 74 return TRUE; 75 } 76 77 static BOOL 78 DoTypeFile( 79 IN LPTSTR FileName, 80 IN HANDLE hConsoleOut, 81 IN BOOL bNoFileName, 82 IN BOOL bPaging) 83 { 84 HANDLE hFile; 85 BOOL bIsFile; 86 DWORD dwFileSize; 87 DWORD dwFilePos; 88 DWORD dwRet; 89 LPTSTR errmsg; 90 TCHAR buff[256]; 91 92 hFile = CreateFile(FileName, 93 GENERIC_READ, 94 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 95 OPEN_EXISTING, 96 FILE_ATTRIBUTE_NORMAL, NULL); 97 98 if (hFile == INVALID_HANDLE_VALUE) 99 { 100 // FIXME: Use ErrorMessage() ? 101 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 102 FORMAT_MESSAGE_IGNORE_INSERTS | 103 FORMAT_MESSAGE_FROM_SYSTEM, 104 NULL, 105 GetLastError(), 106 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 107 (LPTSTR)&errmsg, 108 0, 109 NULL); 110 ConErrPrintf(_T("%s - %s"), FileName, errmsg); 111 LocalFree(errmsg); 112 nErrorLevel = 1; 113 return TRUE; 114 } 115 116 /* 117 * When reading from a file, retrieve its original size, so that 118 * we can stop reading it once we are beyond its original ending. 119 * This allows avoiding an infinite read loop in case the output 120 * of the file is redirected back to it. 121 * If we read from somewhere else (device, ...) don't do anything; 122 * we will stop when ReadFile() fails (e.g. when Ctrl-Z is seen...). 123 */ 124 bIsFile = ((GetFileType(hFile) & ~FILE_TYPE_REMOTE) == FILE_TYPE_DISK); 125 if (bIsFile) 126 { 127 dwFileSize = GetFileSize(hFile, NULL); 128 if ((dwFileSize == INVALID_FILE_SIZE) && 129 (GetLastError() != ERROR_SUCCESS)) 130 { 131 WARN("Error when retrieving file size, or size too large (%d)\n", 132 dwFileSize); 133 dwFileSize = 0; 134 } 135 dwFilePos = SetFilePointer(hFile, 0, NULL, FILE_BEGIN); 136 if ((dwFilePos == INVALID_SET_FILE_POINTER) && 137 (GetLastError() != ERROR_SUCCESS)) 138 { 139 WARN("Error when setting file pointer\n"); 140 dwFilePos = 0; 141 } 142 } 143 else 144 { 145 dwFileSize = dwFilePos = 0; 146 } 147 148 /* 149 * Display the file name on StdErr if required, so that if StdOut 150 * alone is redirected, we can obtain the file contents only. 151 */ 152 if (!bNoFileName) 153 ConErrPrintf(_T("\n%s\n\n\n"), FileName); 154 155 if (bPaging) 156 { 157 while (FileGetString(hFile, buff, ARRAYSIZE(buff))) 158 { 159 if (!ConOutPrintfPaging(FALSE, _T("%s"), buff)) 160 { 161 bCtrlBreak = FALSE; 162 CloseHandle(hFile); 163 nErrorLevel = 1; 164 return FALSE; 165 } 166 167 /* 168 * If we read from a file, check where we are and stop 169 * once we are beyond the original end of the file. 170 */ 171 if (bIsFile) 172 { 173 dwFilePos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); 174 if ((dwFilePos == INVALID_SET_FILE_POINTER) && 175 (GetLastError() != ERROR_SUCCESS)) 176 { 177 WARN("Error when getting file pointer\n"); 178 break; 179 } 180 if (dwFilePos >= dwFileSize) 181 break; 182 } 183 } 184 } 185 else 186 { 187 while (ReadFile(hFile, buff, sizeof(buff), &dwRet, NULL) && dwRet > 0) 188 { 189 WriteFile(hConsoleOut, buff, dwRet, &dwRet, NULL); 190 if (bCtrlBreak) 191 { 192 bCtrlBreak = FALSE; 193 CloseHandle(hFile); 194 nErrorLevel = 1; 195 return FALSE; 196 } 197 198 /* 199 * If we read from a file, check where we are and stop 200 * once we are beyond the original end of the file. 201 */ 202 if (bIsFile) 203 { 204 dwFilePos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); 205 if ((dwFilePos == INVALID_SET_FILE_POINTER) && 206 (GetLastError() != ERROR_SUCCESS)) 207 { 208 WARN("Error when getting file pointer\n"); 209 break; 210 } 211 if (dwFilePos >= dwFileSize) 212 break; 213 } 214 } 215 } 216 217 CloseHandle(hFile); 218 return TRUE; 219 } 220 221 INT cmd_type(LPTSTR param) 222 { 223 INT argc, i; 224 LPTSTR* argv; 225 LPTSTR errmsg; 226 HANDLE hConsoleOut; 227 BOOL bNoFileName = FALSE; 228 BOOL bPaging = FALSE; 229 BOOL bFileFound; 230 DWORD dwLastError; 231 UINT nFileSpecs = 0; 232 HANDLE hFind; 233 WIN32_FIND_DATA FindData; 234 235 if (!_tcsncmp(param, _T("/?"), 2)) 236 { 237 ConOutResPaging(TRUE, STRING_TYPE_HELP1); 238 return 0; 239 } 240 241 if (!*param) 242 { 243 error_req_param_missing(); 244 return 1; 245 } 246 247 /* Parse the command line. We will manually expand any file specification present. */ 248 argv = split(param, &argc, FALSE, FALSE); 249 250 /* Loop through the options, count also the specified number of file specifications */ 251 for (i = 0; i < argc; ++i) 252 { 253 if (argv[i][0] == _T('/')) 254 { 255 if (_tcslen(argv[i]) == 2) 256 { 257 switch (_totupper(argv[i][1])) 258 { 259 case _T('N'): 260 bNoFileName = TRUE; 261 continue; 262 263 case _T('P'): 264 bPaging = TRUE; 265 continue; 266 } 267 } 268 269 // error_invalid_switch(argv[i] + 1); 270 ConErrResPrintf(STRING_TYPE_ERROR, argv[i] + 1); 271 nErrorLevel = 1; 272 goto Quit; 273 } 274 275 /* This should be a file specification */ 276 ++nFileSpecs; 277 } 278 279 nErrorLevel = 0; 280 281 hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); 282 283 /* Reset paging state */ 284 if (bPaging) 285 ConOutPrintfPaging(TRUE, _T("")); 286 287 /* Now loop through the files */ 288 for (i = 0; i < argc; ++i) 289 { 290 /* Skip the options */ 291 if (argv[i][0] == _T('/')) 292 continue; 293 294 /* If wildcards are present in this file specification, perform a file enumeration */ 295 if (_tcschr(argv[i], _T('*')) || _tcschr(argv[i], _T('?'))) 296 { 297 dwLastError = ERROR_SUCCESS; 298 bFileFound = FALSE; 299 300 hFind = FindFirstFile(argv[i], &FindData); 301 302 if (hFind != INVALID_HANDLE_VALUE) 303 { 304 /* Loop through all the files */ 305 do 306 { 307 /* Ignore any directory silently */ 308 if (!_tcscmp(FindData.cFileName, _T(".")) || 309 !_tcscmp(FindData.cFileName, _T("..")) || 310 (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 311 { 312 continue; 313 } 314 315 bFileFound = TRUE; 316 if (!DoTypeFile(FindData.cFileName, hConsoleOut, bNoFileName, bPaging)) 317 { 318 FindClose(hFind); 319 goto Quit; 320 } 321 322 } while (FindNextFile(hFind, &FindData)); 323 324 FindClose(hFind); 325 } 326 327 /* 328 * Return an error if the file specification could not be resolved, 329 * or no actual files were encountered (but only directories). 330 */ 331 if (hFind == INVALID_HANDLE_VALUE) 332 dwLastError = GetLastError(); 333 else if (!bFileFound) 334 dwLastError = ERROR_FILE_NOT_FOUND; 335 336 if (dwLastError != ERROR_SUCCESS) 337 { 338 // FIXME: Use ErrorMessage() ? 339 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 340 FORMAT_MESSAGE_IGNORE_INSERTS | 341 FORMAT_MESSAGE_FROM_SYSTEM, 342 NULL, 343 dwLastError, 344 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 345 (LPTSTR)&errmsg, 346 0, 347 NULL); 348 ConErrPrintf(_T("%s - %s"), argv[i], errmsg); 349 LocalFree(errmsg); 350 nErrorLevel = 1; 351 } 352 } 353 else 354 { 355 if (!DoTypeFile(argv[i], hConsoleOut, (bNoFileName || (nFileSpecs <= 1)), bPaging)) 356 goto Quit; 357 } 358 359 /* Continue with the next file specification */ 360 } 361 362 Quit: 363 freep(argv); 364 return nErrorLevel; 365 } 366 367 #endif 368