Reactos
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
33static BOOL
34FileGetString(
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
77static BOOL
78DoTypeFile(
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
221INT 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
362Quit:
363 freep(argv);
364 return nErrorLevel;
365}
366
367#endif