changes to make cmd compile (not link)
[reactos.git] / reactos / apps / utils / 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
29 #include "config.h"
30
31 #include <windows.h>
32 #include <tchar.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36
37 #include "cmd.h"
38
39
40 /*
41 * get a character out-of-band and honor Ctrl-Break characters
42 */
43 TCHAR cgetchar (VOID)
44 {
45 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
46 INPUT_RECORD irBuffer;
47 DWORD dwRead;
48
49 do
50 {
51 WaitForSingleObject (hInput, INFINITE);
52 ReadConsoleInput (hInput, &irBuffer, 1, &dwRead);
53 if ((irBuffer.EventType == KEY_EVENT) &&
54 (irBuffer.Event.KeyEvent.bKeyDown == TRUE))
55 {
56 if ((irBuffer.Event.KeyEvent.dwControlKeyState &
57 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &
58 (irBuffer.Event.KeyEvent.wVirtualKeyCode == 'C'))
59 bCtrlBreak = TRUE;
60
61 break;
62 }
63 }
64 while (TRUE);
65
66 #ifdef __REACTOS__
67 return irBuffer.Event.KeyEvent.AsciiChar;
68 #else
69 #ifndef _UNICODE
70 return irBuffer.Event.KeyEvent.uChar.AsciiChar;
71 #else
72 return irBuffer.Event.KeyEvent.uChar.UnicodeChar;
73 #endif /* _UNICODE */
74 #endif /* __REACTOS__ */
75 }
76
77
78 /*
79 * Check if Ctrl-Break was pressed during the last calls
80 */
81
82 BOOL CheckCtrlBreak (INT mode)
83 {
84 static BOOL bLeaveAll = FALSE; /* leave all batch files */
85 TCHAR c;
86
87 switch (mode)
88 {
89 case BREAK_OUTOFBATCH:
90 bLeaveAll = 0;
91 return FALSE;
92
93 case BREAK_BATCHFILE:
94 if (bLeaveAll)
95 return TRUE;
96
97 if (!bCtrlBreak)
98 return FALSE;
99
100 /* we need to be sure the string arrives on the screen! */
101 do
102 ConOutPuts (_T("\r\nCtrl-Break pressed. Cancel batch file? (Yes/No/All) "));
103 while (!_tcschr ("YNA\3", c = _totupper (cgetchar())) || !c);
104
105 ConOutPuts (_T("\r\n"));
106
107 if (c == _T('N'))
108 return bCtrlBreak = FALSE; /* ignore */
109
110 /* leave all batch files */
111 bLeaveAll = ((c == _T('A')) || (c == _T('\3')));
112 break;
113
114 case BREAK_INPUT:
115 if (!bCtrlBreak)
116 return FALSE;
117 break;
118 }
119
120 /* state processed */
121 bCtrlBreak = FALSE;
122 return TRUE;
123 }
124
125
126 /*
127 * split - splits a line up into separate arguments, deliminators
128 * are spaces and slashes ('/').
129 */
130
131 LPTSTR *split (LPTSTR s, LPINT args)
132 {
133 LPTSTR *arg;
134 LPTSTR *p;
135 LPTSTR start;
136 LPTSTR q;
137 INT ac;
138 INT len;
139 BOOL bQuoted = FALSE;
140
141 arg = malloc (sizeof (LPTSTR));
142 if (!arg)
143 return NULL;
144 *arg = NULL;
145
146 ac = 0;
147 while (*s)
148 {
149 /* skip leading spaces */
150 while (*s && (_istspace (*s) || _istcntrl (*s)))
151 ++s;
152
153 /* if quote (") then set bQuoted */
154 if (*s == _T('\"'))
155 {
156 ++s;
157 bQuoted = TRUE;
158 }
159
160 start = s;
161
162 /* the first character can be '/' */
163 if (*s == _T('/'))
164 ++s;
165
166 /* skip to next word delimiter or start of next option */
167 if (bQuoted)
168 {
169 while (_istprint (*s) && (*s != _T('\"')) && (*s != _T('/')))
170 ++s;
171 }
172 else
173 {
174 while (_istprint (*s) && !_istspace (*s) && (*s != _T('/')))
175 ++s;
176 }
177
178 /* a word was found */
179 if (s != start)
180 {
181 /* add new entry for new argument */
182 arg = realloc (p = arg, (ac + 2) * sizeof (LPTSTR));
183 if (!arg)
184 {
185 freep (p);
186 return NULL;
187 }
188
189 /* create new entry */
190 q = arg[ac] = malloc (((len = s - start) + 1) * sizeof (TCHAR));
191 arg[++ac] = NULL;
192 if (!q)
193 {
194 freep (arg);
195 return NULL;
196 }
197 memcpy (q, start, len * sizeof (TCHAR));
198 q[len] = _T('\0');
199 }
200
201 /* adjust string pointer if quoted (") */
202 if (bQuoted)
203 {
204 ++s;
205 bQuoted = FALSE;
206 }
207 }
208
209 *args = ac;
210
211 return arg;
212 }
213
214
215 /*
216 * freep -- frees memory used for a call to split
217 *
218 */
219 VOID freep (LPTSTR *p)
220 {
221 LPTSTR *q;
222
223 if (!p)
224 return;
225
226 q = p;
227 while (*q)
228 free(*q++);
229
230 free(p);
231 }
232
233
234 LPTSTR stpcpy (LPTSTR dest, LPTSTR src)
235 {
236 _tcscpy (dest, src);
237 return (dest + _tcslen (src));
238 }
239
240
241
242 /*
243 * Checks if a path is valid (accessible)
244 */
245
246 BOOL IsValidPathName (LPCTSTR pszPath)
247 {
248 TCHAR szOldPath[MAX_PATH];
249 BOOL bResult;
250
251 GetCurrentDirectory (MAX_PATH, szOldPath);
252 bResult = SetCurrentDirectory (pszPath);
253
254 SetCurrentDirectory (szOldPath);
255
256 return bResult;
257 }
258
259
260 /*
261 * Checks if a file exists (accessible)
262 */
263
264 BOOL IsValidFileName (LPCTSTR pszPath)
265 {
266 return (GetFileAttributes (pszPath) != 0xFFFFFFFF);
267 }
268
269
270 BOOL IsValidDirectory (LPCTSTR pszPath)
271 {
272 return (GetFileAttributes (pszPath) & FILE_ATTRIBUTE_DIRECTORY);
273 }
274
275
276 BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength)
277 {
278 LPTSTR lpString;
279 TCHAR ch;
280 DWORD dwRead;
281
282 lpString = lpBuffer;
283
284 while ((--nBufferLength > 0) &&
285 ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead)
286 {
287 *lpString++ = ch;
288 if (ch == _T('\r'))
289 {
290 /* overread '\n' */
291 ReadFile (hFile, &ch, 1, &dwRead, NULL);
292 break;
293 }
294 }
295
296 if (!dwRead && lpString == lpBuffer)
297 return FALSE;
298
299 *lpString++ = _T('\0');
300
301 return TRUE;
302 }