update for HEAD-2003050101
[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 ("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         LPTSTR lpString;
375         TCHAR  ch;
376         DWORD  dwRead;
377
378         lpString = lpBuffer;
379
380         while ((--nBufferLength >  0) &&
381                    ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead)
382         {
383                 if (ch == _T('\r'))
384                 {
385                         /* overread '\n' */
386                         ReadFile (hFile, &ch, 1, &dwRead, NULL);
387                         break;
388                 }
389                 *lpString++ = ch;
390         }
391
392         if (!dwRead && lpString == lpBuffer)
393                 return FALSE;
394
395         *lpString++ = _T('\0');
396
397         return TRUE;
398 }
399
400 #ifndef __REACTOS__
401 /*
402  * GetConsoleWindow - returns the handle to the current console window
403  */
404 HWND GetConsoleWindow (VOID)
405 {
406         TCHAR original[256];
407         TCHAR temp[256];
408         HWND h=0;
409
410         if(h)
411                 return h;
412
413         GetConsoleTitle (original, sizeof(original));
414
415         _tcscpy (temp, original);
416         _tcscat (temp, _T("-xxx   "));
417
418         if (FindWindow (0, temp) == NULL )
419         {
420                 SetConsoleTitle (temp);
421                 Sleep (0);
422
423                 while(!(h = FindWindow (0, temp)))
424                         ;
425
426                 SetConsoleTitle (original);
427         }
428
429         return h;
430 }
431 #endif
432
433
434 INT PagePrompt (VOID)
435 {
436         INPUT_RECORD ir;
437
438         ConOutPrintf ("Press a key to continue...\n");
439
440         RemoveBreakHandler ();
441         ConInDisable ();
442
443         do
444         {
445                 ConInKey (&ir);
446         }
447         while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
448                (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
449                (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
450
451         AddBreakHandler ();
452         ConInEnable ();
453
454         if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
455             ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
456              (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
457                 return PROMPT_BREAK;
458
459         return PROMPT_YES;
460 }
461
462
463 INT FilePromptYN (LPTSTR szFormat, ...)
464 {
465         TCHAR szOut[512];
466         va_list arg_ptr;
467 //        TCHAR cKey = 0;
468 //        LPTSTR szKeys = _T("yna");
469
470         TCHAR szIn[10];
471         LPTSTR p;
472
473         va_start (arg_ptr, szFormat);
474         _vstprintf (szOut, szFormat, arg_ptr);
475         va_end (arg_ptr);
476
477         ConOutPrintf (szFormat);
478
479 /* preliminary fix */
480         ConInString (szIn, 10);
481         ConOutPrintf (_T("\n"));
482
483         _tcsupr (szIn);
484         for (p = szIn; _istspace (*p); p++)
485                 ;
486
487         if (*p == _T('Y'))
488                 return PROMPT_YES;
489         else if (*p == _T('N'))
490                 return PROMPT_NO;
491 #if 0
492         else if (*p == _T('\03'))
493                 return PROMPT_BREAK;
494 #endif
495
496         return PROMPT_NO;
497
498
499 /* unfinished sollution */
500 #if 0
501         RemoveBreakHandler ();
502         ConInDisable ();
503
504         do
505         {
506                 ConInKey (&ir);
507                 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
508                 if (_tcschr (szKeys, cKey[0]) == NULL)
509                         cKey = 0;                        
510
511
512         }
513         while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
514                (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
515                (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
516
517         AddBreakHandler ();
518         ConInEnable ();
519
520         if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
521             ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
522              (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
523                 return PROMPT_BREAK;
524
525         return PROMPT_YES;
526 #endif
527 }
528
529
530 INT FilePromptYNA (LPTSTR szFormat, ...)
531 {
532         TCHAR szOut[512];
533         va_list arg_ptr;
534 //        TCHAR cKey = 0;
535 //        LPTSTR szKeys = _T("yna");
536
537         TCHAR szIn[10];
538         LPTSTR p;
539
540         va_start (arg_ptr, szFormat);
541         _vstprintf (szOut, szFormat, arg_ptr);
542         va_end (arg_ptr);
543
544         ConOutPrintf (szFormat);
545
546 /* preliminary fix */
547         ConInString (szIn, 10);
548         ConOutPrintf (_T("\n"));
549
550         _tcsupr (szIn);
551         for (p = szIn; _istspace (*p); p++)
552                 ;
553
554         if (*p == _T('Y'))
555                 return PROMPT_YES;
556         else if (*p == _T('N'))
557                 return PROMPT_NO;
558         if (*p == _T('A'))
559                 return PROMPT_ALL;
560 #if 0
561         else if (*p == _T('\03'))
562                 return PROMPT_BREAK;
563 #endif
564
565         return PROMPT_NO;
566
567
568 /* unfinished sollution */
569 #if 0
570         RemoveBreakHandler ();
571         ConInDisable ();
572
573         do
574         {
575                 ConInKey (&ir);
576                 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
577                 if (_tcschr (szKeys, cKey[0]) == NULL)
578                         cKey = 0;                        
579
580
581         }
582         while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
583                (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
584                (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
585
586         AddBreakHandler ();
587         ConInEnable ();
588
589         if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
590             ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
591              (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
592                 return PROMPT_BREAK;
593
594         return PROMPT_YES;
595 #endif
596 }
597
598 /* EOF */