SYSTEM_TIME_ZONE_INFORMATION added.
[reactos.git] / rosapps / cmd / alias.c
1 /*
2 * ALIAS.C - alias administration module.
3 *
4 *
5 * History:
6 *
7 * 02/02/1996 (Oliver Mueller)
8 * started.
9 *
10 * 02/03/1996 (Oliver Mueller)
11 * Added sorting algorithm and case sensitive substitution by using
12 * partstrupr().
13 *
14 * 27 Jul 1998 John P. Price
15 * added config.h include
16 * added ifdef's to disable aliases
17 *
18 * 09-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
19 * Fixed crash when removing an alias in DeleteAlias().
20 * Added help text ("/?").
21 *
22 * 14-Jan-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
23 * Clean up and Unicode safe!
24 *
25 * 24-Jan-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
26 * Redirection safe!
27 */
28
29
30 #include "config.h"
31
32 #ifdef FEATURE_ALIASES
33
34 #include <windows.h>
35 #include <tchar.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 #include "cmd.h"
41
42
43 typedef struct tagALIAS
44 {
45 struct tagALIAS *next;
46 LPTSTR lpName;
47 LPTSTR lpSubst;
48 DWORD dwUsed;
49 } ALIAS, *LPALIAS;
50
51
52 static LPALIAS lpFirst = NULL;
53 static LPALIAS lpLast = NULL;
54 static DWORD dwUsed = 0;
55
56
57 /* module internal functions */
58 /* strlwr only for first word in string */
59 static VOID
60 partstrlwr (LPTSTR str)
61 {
62 LPTSTR c = str;
63 while (*c && !_istspace (*c) && *c != _T('='))
64 {
65 *c = _totlower (*c);
66 c++;
67 }
68 }
69
70
71 static VOID
72 PrintAlias (VOID)
73 {
74 LPALIAS ptr = lpFirst;
75 while (ptr)
76 {
77 ConOutPrintf (_T("%s=%s\n"), ptr->lpName, ptr->lpSubst);
78 ptr = ptr->next;
79 }
80 }
81
82
83 static VOID
84 DeleteAlias (LPTSTR pszName)
85 {
86 LPALIAS ptr = lpFirst;
87 LPALIAS prev = NULL;
88
89 while (ptr)
90 {
91 if (!_tcsicmp (ptr->lpName, pszName))
92 {
93 if (prev)
94 prev->next = ptr->next;
95 else
96 lpFirst = ptr->next;
97 free (ptr->lpName);
98 free (ptr->lpSubst);
99 free (ptr);
100 return;
101 }
102 prev = ptr;
103 ptr = ptr->next;
104 }
105 }
106
107
108 static VOID
109 AddAlias (LPTSTR name, LPTSTR subst)
110 {
111 LPALIAS ptr = lpFirst;
112 LPALIAS prev, entry;
113 LPTSTR s;
114
115 while (ptr)
116 {
117 if (!_tcsicmp (ptr->lpName, name))
118 {
119 s = (LPTSTR)malloc ((_tcslen (subst) + 1)*sizeof(TCHAR));
120 if (!s)
121 {
122 error_out_of_memory ();
123 return;
124 }
125
126 free (ptr->lpSubst);
127 ptr->lpSubst = s;
128 _tcscpy (ptr->lpSubst, subst);
129 return;
130 }
131 ptr = ptr->next;
132 }
133
134 ptr = (LPALIAS)malloc (sizeof (ALIAS));
135 if (!ptr)
136 return;
137
138 ptr->next = 0;
139
140 ptr->lpName = (LPTSTR)malloc ((_tcslen (name) + 1)*sizeof(TCHAR));
141 if (!ptr->lpName)
142 {
143 error_out_of_memory ();
144 free (ptr);
145 return;
146 }
147 _tcscpy (ptr->lpName, name);
148
149 ptr->lpSubst = (LPTSTR)malloc ((_tcslen (subst) + 1)*sizeof(TCHAR));
150 if (!ptr->lpSubst)
151 {
152 error_out_of_memory ();
153 free (ptr->lpName);
154 free (ptr);
155 return;
156 }
157 _tcscpy (ptr->lpSubst, subst);
158
159 /* it's necessary for recursive substitution */
160 partstrlwr (ptr->lpSubst);
161
162 ptr->dwUsed = 0;
163
164 /* Alias table must be sorted!
165 * Here a little example:
166 * command line = "ls -c"
167 * If the entries are
168 * ls=dir
169 * ls -c=ls /w
170 * command line will be expanded to "dir -c" which is not correct.
171 * If the entries are sortet as
172 * ls -c=ls /w
173 * ls=dir
174 * it will be expanded to "dir /w" which is a valid DOS command.
175 */
176 entry = lpFirst;
177 prev = 0;
178 while (entry)
179 {
180 if (_tcsicmp (ptr->lpName, entry->lpName) > 0)
181 {
182 if (prev)
183 {
184 prev->next = ptr;
185 ptr->next = entry;
186 }
187 else
188 {
189 ptr->next = entry;
190 lpFirst = ptr;
191 }
192 return;
193 }
194 prev = entry;
195 entry = entry->next;
196 }
197
198 /* The new entry is the smallest (or the first) and must be
199 * added to the end of the list.
200 */
201 if (!lpFirst)
202 lpFirst = ptr;
203 else
204 lpLast->next = ptr;
205 lpLast = ptr;
206
207 return;
208 }
209
210
211 VOID InitializeAlias (VOID)
212 {
213 lpFirst = NULL;
214 lpLast = NULL;
215 dwUsed = 0;
216 }
217
218 VOID DestroyAlias (VOID)
219 {
220 if (lpFirst == NULL)
221 return;
222
223 while (lpFirst->next != NULL)
224 {
225 lpLast = lpFirst;
226 lpFirst = lpLast->next;
227
228 free (lpLast->lpName);
229 free (lpLast->lpSubst);
230 free (lpLast);
231 }
232
233 free (lpFirst->lpName);
234 free (lpFirst->lpSubst);
235 free (lpFirst);
236
237 lpFirst = NULL;
238 lpLast = NULL;
239 dwUsed = 0;
240 }
241
242 /* specified routines */
243 VOID ExpandAlias (LPTSTR cmd, INT maxlen)
244 {
245 unsigned n = 0,
246 m,
247 i,
248 len;
249 short d = 1;
250 LPALIAS ptr = lpFirst;
251
252 dwUsed++;
253 if (dwUsed == 0)
254 {
255 while (ptr)
256 ptr->dwUsed = 0;
257 ptr = lpFirst;
258 dwUsed = 1;
259 }
260
261 /* skipping white spaces */
262 while (_istspace (cmd[n]))
263 n++;
264
265 partstrlwr (&cmd[n]);
266
267 if (!_tcsncmp (&cmd[n], _T("NOALIAS"), 7) &&
268 (_istspace (cmd[n + 7]) || cmd[n + 7] == _T('\0')))
269 {
270 memmove (cmd, &cmd[n + 7], (_tcslen (&cmd[n + 7]) + 1) * sizeof (TCHAR));
271 return;
272 }
273
274 /* substitution loop */
275 while (d)
276 {
277 d = 0;
278 while (ptr)
279 {
280 len = _tcslen (ptr->lpName);
281 if (!_tcsncmp (&cmd[n], ptr->lpName, len) &&
282 (_istspace (cmd[n + len]) || cmd[n + len] == _T('\0')) &&
283 ptr->dwUsed != dwUsed)
284 {
285 m = _tcslen (ptr->lpSubst);
286 if ((int)(_tcslen (cmd) - len + m - n) > maxlen)
287 {
288 ConErrPrintf (_T("Command line too long after alias expansion!\n"));
289 /* the parser won't cause any problems with an empty line */
290 cmd[0] = _T('\0');
291 }
292 else
293 {
294 memmove (&cmd[m], &cmd[n + len], (_tcslen(&cmd[n + len]) + 1) * sizeof (TCHAR));
295 for (i = 0; i < m; i++)
296 cmd[i] = ptr->lpSubst[i];
297 ptr->dwUsed = dwUsed;
298 /* whitespaces are removed! */
299 n = 0;
300 d = 1;
301 }
302 }
303 ptr = ptr->next;
304 }
305 }
306 }
307
308
309 INT CommandAlias (LPTSTR cmd, LPTSTR param)
310 {
311 LPTSTR ptr;
312
313 if (!_tcsncmp (param, _T("/?"), 2))
314 {
315 ConOutPuts (_T("Sets, removes or shows aliases.\n"
316 "\n"
317 "ALIAS [alias=[command]]\n"
318 "\n"
319 " alias Name for an alias.\n"
320 " command Text to be substituted for an alias.\n"
321 "\n"
322 // "For example:\n"
323 "To list all aliases:\n"
324 " ALIAS\n\n"
325 "To set a new or replace an existing alias:\n"
326 " ALIAS da=dir a:\n\n"
327 "To remove an alias from the alias list:\n"
328 " ALIAS da="
329 // "Type ALIAS without a parameter to display the alias list.\n"
330 ));
331 return 0;
332 }
333
334 if (param[0] == _T('\0'))
335 {
336 PrintAlias ();
337 return 0;
338 }
339
340 /* error if no '=' found */
341 if ((ptr = _tcschr (param, _T('='))) == 0)
342 return 1;
343
344 /* Split rest into name and substitute */
345 *ptr++ = _T('\0');
346
347 partstrlwr (param);
348
349 if (ptr[0] == _T('\0'))
350 DeleteAlias (param);
351 else
352 AddAlias (param, ptr);
353
354 return 0;
355 }
356 #endif