update for HEAD-2003091401
[reactos.git] / subsys / system / cmd / misc.c
1 /*
2  *  MISC.C - misc. functions.
3  *
4  *
5  *  History:
6  *
7  *    07/12/98 (Rob Lake)
8  *        started
9  *
10  *    07/13/98 (Rob Lake)
11  *        moved functions in here
12  *
13  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
14  *        added config.h include
15  *
16  *    18-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
17  *        Changed split() to accept quoted arguments.
18  *        Removed parse_firstarg().
19  *
20  *    23-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
21  *        Fixed an ugly bug in split(). In rare cases (last character
22  *        of the string is a space) it ignored the NULL character and
23  *        tried to add the following to the argument list.
24  *
25  *    28-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
26  *        FileGetString() seems to be working now.
27  *
28  *    06-Nov-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
29  *        Added PagePrompt() and FilePrompt().
30  */
31
32 #include "config.h"
33
34 #include <windows.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <tchar.h>
40
41 #include "cmd.h"
42
43
44 /*
45  * get a character out-of-band and honor Ctrl-Break characters
46  */
47 TCHAR cgetchar (VOID)
48 {
49         HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
50         INPUT_RECORD irBuffer;
51         DWORD  dwRead;
52
53         do
54         {
55                 ReadConsoleInput (hInput, &irBuffer, 1, &dwRead);
56                 if ((irBuffer.EventType == KEY_EVENT) &&
57                         (irBuffer.Event.KeyEvent.bKeyDown == TRUE))
58                 {
59                         if ((irBuffer.Event.KeyEvent.dwControlKeyState &
60                                  (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &
61                                 (irBuffer.Event.KeyEvent.wVirtualKeyCode == 'C'))
62                                 bCtrlBreak = TRUE;
63
64                         break;
65                 }
66         }
67         while (TRUE);
68
69 #ifndef _UNICODE
70         return irBuffer.Event.KeyEvent.uChar.AsciiChar;
71 #else
72         return irBuffer.Event.KeyEvent.uChar.UnicodeChar;
73 #endif /* _UNICODE */
74 }
75
76
77 /*
78  * Check if Ctrl-Break was pressed during the last calls
79  */
80
81 BOOL CheckCtrlBreak (INT mode)
82 {
83         static BOOL bLeaveAll = FALSE; /* leave all batch files */
84         TCHAR c;
85
86         switch (mode)
87         {
88                 case BREAK_OUTOFBATCH:
89                         bLeaveAll = 0;
90                         return FALSE;
91
92                 case BREAK_BATCHFILE:
93                         if (bLeaveAll)
94                                 return TRUE;
95
96                         if (!bCtrlBreak)
97                                 return FALSE;
98
99                         /* we need to be sure the string arrives on the screen! */
100                         do
101                                 ConOutPuts (_T("\r\nCtrl-Break pressed.  Cancel batch file? (Yes/No/All) "));
102                         while (!_tcschr (_T("YNA\3"), c = _totupper (cgetchar())) || !c);
103
104                         ConOutPuts (_T("\r\n"));
105
106                         if (c == _T('N'))
107                                 return bCtrlBreak = FALSE; /* ignore */
108
109                         /* leave all batch files */
110                         bLeaveAll = ((c == _T('A')) || (c == _T('\3')));
111                         break;
112
113                 case BREAK_INPUT:
114                         if (!bCtrlBreak)
115                                 return FALSE;
116                         break;
117         }
118
119         /* state processed */
120         bCtrlBreak = FALSE;
121         return TRUE;
122 }
123
124 /* add new entry for new argument */
125 static BOOL add_entry (LPINT ac, LPTSTR **arg, LPCTSTR entry)
126 {
127         LPTSTR q;
128         LPTSTR *oldarg;
129
130         q = malloc ((_tcslen(entry) + 1) * sizeof (TCHAR));
131         if (NULL == q)
132         {
133                 return FALSE;
134         }
135         _tcscpy (q, entry);
136                 
137         oldarg = *arg;
138         *arg = realloc (oldarg, (*ac + 2) * sizeof (LPTSTR));
139         if (NULL == *arg)
140         {
141                 *arg = oldarg;
142                 return FALSE;
143         }
144
145         /* save new entry */
146         (*arg)[*ac] = q;
147         (*arg)[++(*ac)] = NULL;
148
149         return TRUE;
150 }
151
152 static BOOL expand (LPINT ac, LPTSTR **arg, LPCTSTR pattern)
153 {
154         HANDLE hFind;
155         WIN32_FIND_DATA FindData;
156         BOOL ok;
157         LPCTSTR pathend;
158         LPTSTR dirpart, fullname;
159
160         pathend = _tcsrchr (pattern, _T('\\'));
161         if (NULL != pathend)
162         {
163                 dirpart = malloc((pathend - pattern + 2) * sizeof(TCHAR));
164                 if (NULL == dirpart)
165                 {
166                         return FALSE;
167                 }
168                 memcpy(dirpart, pattern, pathend - pattern + 1);
169                 dirpart[pathend - pattern + 1] = '\0';
170         }
171         else
172         {
173                 dirpart = NULL;
174         }
175         hFind = FindFirstFile (pattern, &FindData);
176         if (INVALID_HANDLE_VALUE != hFind)
177         {
178                 do
179                 {
180                         if (NULL != dirpart)
181                         {
182                                 fullname = malloc((_tcslen(dirpart) + _tcslen(FindData.cFileName) + 1) * sizeof(TCHAR));
183                                 if (NULL == fullname)
184                                 {
185                                         ok = FALSE;
186                                 }
187                                 else
188                                 {
189                                         _tcscat (_tcscpy (fullname, dirpart), FindData.cFileName);
190                                         ok = add_entry(ac, arg, fullname);
191                                         free (fullname);
192                                 }
193                         }
194                         else
195                         {
196                                 ok = add_entry(ac, arg, FindData.cFileName);
197                         }
198                 } while (FindNextFile (hFind, &FindData) && ok);
199                 FindClose (hFind);
200         }
201         else
202         {
203                 ok = add_entry(ac, arg, pattern);
204         }
205
206         if (NULL != dirpart)
207         {
208                 free (dirpart);
209         }
210
211         return ok;
212 }
213
214 /*
215  * split - splits a line up into separate arguments, deliminators
216  *         are spaces and slashes ('/').
217  */
218
219 LPTSTR *split (LPTSTR s, LPINT args, BOOL expand_wildcards)
220 {
221         LPTSTR *arg;
222         LPTSTR start;
223         LPTSTR q;
224         INT  ac;
225         INT  len;
226         BOOL bQuoted = FALSE;
227
228         arg = malloc (sizeof (LPTSTR));
229         if (!arg)
230                 return NULL;
231         *arg = NULL;
232
233         ac = 0;
234         while (*s)
235         {
236                 /* skip leading spaces */
237                 while (*s && (_istspace (*s) || _istcntrl (*s)))
238                         ++s;
239
240                 /* if quote (") then set bQuoted */
241                 if (*s == _T('\"'))
242                 {
243                         ++s;
244                         bQuoted = TRUE;
245                 }
246
247                 start = s;
248
249                 /* the first character can be '/' */
250                 if (*s == _T('/'))
251                         ++s;
252
253                 /* skip to next word delimiter or start of next option */
254                 if (bQuoted)
255                 {
256                         while (_istprint (*s) && (*s != _T('\"')) && (*s != _T('/')))
257                                 ++s;
258                 }
259                 else
260                 {
261                         while (_istprint (*s) && !_istspace (*s) && (*s != _T('/')))
262                                 ++s;
263                 }
264
265                 /* a word was found */
266                 if (s != start)
267                 {
268                         q = malloc (((len = s - start) + 1) * sizeof (TCHAR));
269                         if (!q)
270                         {
271                                 return NULL;
272                         }
273                         memcpy (q, start, len * sizeof (TCHAR));
274                         q[len] = _T('\0');
275                         if (expand_wildcards && _T('/') != *start &&
276                             (NULL != _tcschr(q, _T('*')) || NULL != _tcschr(q, _T('?'))))
277                         {
278                                 if (! expand(&ac, &arg, q))
279                                 {
280                                         free (q);
281                                         freep (arg);
282                                         return NULL;
283                                 }
284                         }
285                         else
286                         {
287                                 if (! add_entry(&ac, &arg, q))
288                                 {
289                                         free (q);
290                                         freep (arg);
291                                         return NULL;
292                                 }
293                         }
294                         free (q);
295                 }
296
297                 /* adjust string pointer if quoted (") */
298                 if (bQuoted)
299                 {
300                         ++s;
301                         bQuoted = FALSE;
302                 }
303         }
304
305         *args = ac;
306
307         return arg;
308 }
309
310
311 /*
312  * freep -- frees memory used for a call to split
313  *
314  */
315 VOID freep (LPTSTR *p)
316 {
317         LPTSTR *q;
318
319         if (!p)
320                 return;
321
322         q = p;
323         while (*q)
324                 free(*q++);
325
326         free(p);
327 }
328
329
330 LPTSTR stpcpy (LPTSTR dest, LPTSTR src)
331 {
332         _tcscpy (dest, src);
333         return (dest + _tcslen (src));
334 }
335
336
337
338 /*
339  * Checks if a path is valid (accessible)
340  */
341
342 BOOL IsValidPathName (LPCTSTR pszPath)
343 {
344         TCHAR szOldPath[MAX_PATH];
345         BOOL  bResult;
346
347         GetCurrentDirectory (MAX_PATH, szOldPath);
348         bResult = SetCurrentDirectory (pszPath);
349
350         SetCurrentDirectory (szOldPath);
351
352         return bResult;
353 }
354
355
356 /*
357  * Checks if a file exists (accessible)
358  */
359
360 BOOL IsValidFileName (LPCTSTR pszPath)
361 {
362         return (GetFileAttributes (pszPath) != 0xFFFFFFFF);
363 }
364
365
366 BOOL IsValidDirectory (LPCTSTR pszPath)
367 {
368         return (GetFileAttributes (pszPath) & FILE_ATTRIBUTE_DIRECTORY);
369 }
370
371
372 BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength)
373 {
374         LPSTR lpString;
375         CHAR ch;
376         DWORD  dwRead;
377         INT len;
378 #ifdef _UNICODE
379         lpString = alloca(nBufferLength);
380 #else
381         lpString = lpBuffer;
382 #endif
383         len = 0;
384         while ((--nBufferLength >  0) &&
385                    ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead)
386         {
387                 if (ch == '\r')
388                 {
389                         /* overread '\n' */
390                         ReadFile (hFile, &ch, 1, &dwRead, NULL);
391                         break;
392                 }
393                 lpString[len++] = ch;
394         }
395
396         if (!dwRead && !len)
397                 return FALSE;
398
399         lpString[len++] = '\0';
400 #ifdef _UNICODE
401         MultiByteToWideChar(CP_ACP, 0, lpString, len, lpBuffer, len);
402 #endif
403         return TRUE;
404 }
405
406 #ifndef __REACTOS__
407 /*
408  * GetConsoleWindow - returns the handle to the current console window
409  */
410 HWND GetConsoleWindow (VOID)
411 {
412         TCHAR original[256];
413         TCHAR temp[256];
414         HWND h=0;
415
416         if(h)
417                 return h;
418
419         GetConsoleTitle (original, sizeof(original) / sizeof(TCHAR));
420
421         _tcscpy (temp, original);
422         _tcscat (temp, _T("-xxx   "));
423
424         if (FindWindow (0, temp) == NULL )
425         {
426                 SetConsoleTitle (temp);
427                 Sleep (0);
428
429                 while(!(h = FindWindow (0, temp)))
430                         ;
431
432                 SetConsoleTitle (original);
433         }
434
435         return h;
436 }
437 #endif
438
439
440 INT PagePrompt (VOID)
441 {
442         INPUT_RECORD ir;
443
444         ConOutPrintf (_T("Press a key to continue...\n"));
445
446         RemoveBreakHandler ();
447         ConInDisable ();
448
449         do
450         {
451                 ConInKey (&ir);
452         }
453         while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
454                (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
455                (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
456
457         AddBreakHandler ();
458         ConInEnable ();
459
460         if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
461             ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
462              (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
463                 return PROMPT_BREAK;
464
465         return PROMPT_YES;
466 }
467
468
469 INT FilePromptYN (LPTSTR szFormat, ...)
470 {
471         TCHAR szOut[512];
472         va_list arg_ptr;
473 //        TCHAR cKey = 0;
474 //        LPTSTR szKeys = _T("yna");
475
476         TCHAR szIn[10];
477         LPTSTR p;
478
479         va_start (arg_ptr, szFormat);
480         _vstprintf (szOut, szFormat, arg_ptr);
481         va_end (arg_ptr);
482
483         ConOutPrintf (szFormat);
484
485 /* preliminary fix */
486         ConInString (szIn, 10);
487         ConOutPrintf (_T("\n"));
488
489         _tcsupr (szIn);
490         for (p = szIn; _istspace (*p); p++)
491                 ;
492
493         if (*p == _T('Y'))
494                 return PROMPT_YES;
495         else if (*p == _T('N'))
496                 return PROMPT_NO;
497 #if 0
498         else if (*p == _T('\03'))
499                 return PROMPT_BREAK;
500 #endif
501
502         return PROMPT_NO;
503
504
505 /* unfinished sollution */
506 #if 0
507         RemoveBreakHandler ();
508         ConInDisable ();
509
510         do
511         {
512                 ConInKey (&ir);
513                 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
514                 if (_tcschr (szKeys, cKey[0]) == NULL)
515                         cKey = 0;                        
516
517
518         }
519         while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
520                (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
521                (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
522
523         AddBreakHandler ();
524         ConInEnable ();
525
526         if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
527             ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
528              (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
529                 return PROMPT_BREAK;
530
531         return PROMPT_YES;
532 #endif
533 }
534
535
536 INT FilePromptYNA (LPTSTR szFormat, ...)
537 {
538         TCHAR szOut[512];
539         va_list arg_ptr;
540 //        TCHAR cKey = 0;
541 //        LPTSTR szKeys = _T("yna");
542
543         TCHAR szIn[10];
544         LPTSTR p;
545
546         va_start (arg_ptr, szFormat);
547         _vstprintf (szOut, szFormat, arg_ptr);
548         va_end (arg_ptr);
549
550         ConOutPrintf (szFormat);
551
552 /* preliminary fix */
553         ConInString (szIn, 10);
554         ConOutPrintf (_T("\n"));
555
556         _tcsupr (szIn);
557         for (p = szIn; _istspace (*p); p++)
558                 ;
559
560         if (*p == _T('Y'))
561                 return PROMPT_YES;
562         else if (*p == _T('N'))
563                 return PROMPT_NO;
564         if (*p == _T('A'))
565                 return PROMPT_ALL;
566 #if 0
567         else if (*p == _T('\03'))
568                 return PROMPT_BREAK;
569 #endif
570
571         return PROMPT_NO;
572
573
574 /* unfinished sollution */
575 #if 0
576         RemoveBreakHandler ();
577         ConInDisable ();
578
579         do
580         {
581                 ConInKey (&ir);
582                 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
583                 if (_tcschr (szKeys, cKey[0]) == NULL)
584                         cKey = 0;                        
585
586
587         }
588         while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
589                (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
590                (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
591
592         AddBreakHandler ();
593         ConInEnable ();
594
595         if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
596             ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
597              (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
598                 return PROMPT_BREAK;
599
600         return PROMPT_YES;
601 #endif
602 }
603
604 /* EOF */