remove whitespace from end of lines
[reactos.git] / reactos / subsys / system / cmd / history.c
1 /*
2 * HISTORY.C - command line history.
3 *
4 *
5 * History:
6 *
7 * 14/01/95 (Tim Norman)
8 * started.
9 *
10 * 08/08/95 (Matt Rains)
11 * i have cleaned up the source code. changes now bring this source
12 * into guidelines for recommended programming practice.
13 *
14 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
15 * added config.h include
16 *
17 * 25-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
18 * Cleanup!
19 * Unicode and redirection safe!
20 *
21 * 25-Jan-1999 (Paolo Pantaleo <paolopan@freemail.it>)
22 * Added lots of comments (beginning studying the source)
23 * Added command.com's F3 support (see cmdinput.c)
24 *
25 */
26
27
28
29 /*
30 * HISTORY.C - command line history. Second version
31 *
32 *
33 * History:
34 *
35 * 06/12/99 (Paolo Pantaleo <paolopan@freemail.it>)
36 * started.
37 *
38 */
39
40 #include "precomp.h"
41
42 #ifdef FEATURE_HISTORY
43
44 typedef struct tagHISTORY
45 {
46 struct tagHISTORY *prev;
47 struct tagHISTORY *next;
48 LPTSTR string;
49 } HIST_ENTRY, * LPHIST_ENTRY;
50
51 static INT size,
52 max_size=100;
53
54
55
56 static LPHIST_ENTRY Top;
57 static LPHIST_ENTRY Bottom;
58
59
60 static LPHIST_ENTRY curr_ptr=0;
61
62
63 VOID InitHistory(VOID);
64 VOID History_move_to_bottom(VOID);
65 VOID History (INT dir, LPTSTR commandline);
66 VOID CleanHistory(VOID);
67 VOID History_del_current_entry(LPTSTR str);
68
69 /*service functions*/
70 static VOID del(LPHIST_ENTRY item);
71 static VOID add_at_bottom(LPTSTR string);
72 /*VOID add_before_last(LPTSTR string);*/
73 VOID set_size(INT new_size);
74
75
76
77 INT CommandHistory (LPTSTR cmd, LPTSTR param)
78 {
79 LPTSTR tmp;
80 INT tmp_int;
81 LPHIST_ENTRY h_tmp;
82 TCHAR szBuffer[2048];
83
84 tmp=_tcschr(param,_T('/'));
85
86 if (tmp)
87 {
88 param=tmp;
89 switch (_totupper(param[1]))
90 {
91 case _T('F'):/*delete history*/
92 CleanHistory();InitHistory();
93 break;
94
95 case _T('R'):/*read history from standard in*/
96 //hIn=GetStdHandle (STD_INPUT_HANDLE);
97
98 for(;;)
99 {
100 ConInString(szBuffer,sizeof(szBuffer)/sizeof(TCHAR));
101 if (*szBuffer!=_T('\0'))
102 History(0,szBuffer);
103 else
104 break;
105 }
106 break;
107
108 case _T('A'):/*add an antry*/
109 History(0,param+2);
110 break;
111
112 case _T('S'):/*set history size*/
113 if ((tmp_int=_ttoi(param+2)))
114 set_size(tmp_int);
115 break;
116
117 default:
118 return 1;
119 }
120 }
121 else
122 {
123 for (h_tmp = Top->prev; h_tmp != Bottom; h_tmp = h_tmp->prev)
124 ConErrPuts(h_tmp->string);
125 }
126 return 0;
127 }
128
129 VOID set_size(INT new_size)
130 {
131 while (new_size<size)
132 del(Top->prev);
133
134 max_size=new_size;
135 }
136
137
138 VOID InitHistory(VOID)
139 {
140 size=0;
141
142 Top = malloc(sizeof(HIST_ENTRY));
143 Bottom = malloc(sizeof(HIST_ENTRY));
144
145 Top->prev = Bottom;
146 Top->next = NULL;
147 Top->string = NULL;
148
149 Bottom->prev = NULL;
150 Bottom->next = Top;
151 Bottom->string = NULL;
152
153 curr_ptr=Bottom;
154 }
155
156
157
158
159 VOID CleanHistory(VOID)
160 {
161 while (Bottom->next!=Top)
162 del(Bottom->next);
163
164 free(Top);
165 free(Bottom);
166 }
167
168
169 VOID History_del_current_entry(LPTSTR str)
170 {
171 LPHIST_ENTRY tmp;
172
173 if (size == 0)
174 return;
175
176 if (curr_ptr == Bottom)
177 curr_ptr=Bottom->next;
178
179 if (curr_ptr == Top)
180 curr_ptr=Top->prev;
181
182
183 tmp = curr_ptr;
184 curr_ptr = curr_ptr->prev;
185 del(tmp);
186 History(-1, str);
187 }
188
189
190 static
191 VOID del(LPHIST_ENTRY item)
192 {
193 if (item==NULL || item==Top || item==Bottom)
194 {
195 #ifdef _DEBUG
196 DebugPrintf(_T("del in " __FILE__ ": retrning\n"
197 "item is 0x%08x (Bottom is0x%08x)\n"),
198 item, Bottom);
199 #endif
200 return;
201 }
202
203
204
205 /*free string's mem*/
206 if (item->string)
207 free(item->string);
208
209 /*set links in prev and next item*/
210 item->next->prev=item->prev;
211 item->prev->next=item->next;
212
213 free(item);
214
215 size--;
216 }
217
218
219 #if 0
220 static
221 VOID add_before_last(LPTSTR string)
222 {
223 LPHIST_ENTRY tmp,before,after;
224
225 /*delete first entry if maximum number of entries is reached*/
226 while(size>=max_size)
227 del(Top->prev);
228
229 while (_istspace(*string))
230 string++;
231
232 if (*string==_T('\0'))
233 return;
234
235 /*allocte entry and string*/
236 tmp=malloc(sizeof(HIST_ENTRY));
237 tmp->string=malloc((_tcslen(string)+1)*sizeof(TCHAR));
238 _tcscpy(tmp->string,string);
239
240 /*set links*/
241 before=Bottom->next;
242 after=before->next;
243
244 tmp->prev=before;
245 tmp->next=after;
246
247 after->prev=tmp;
248 before->next=tmp;
249
250 /*set new size*/
251 size++;
252
253
254 }
255 #endif/*0*/
256
257 static
258 VOID add_at_bottom(LPTSTR string)
259 {
260
261
262 LPHIST_ENTRY tmp;
263
264
265 /*delete first entry if maximum number of entries is reached*/
266 while(size>=max_size)
267 del(Top->prev);
268
269 while (_istspace(*string))
270 string++;
271
272 if (*string==_T('\0'))
273 return;
274
275
276 /*if new entry is the same than the last do not add it*/
277 if(size)
278 if(_tcscmp(string,Bottom->next->string)==0)
279 return;
280
281
282 /*fill bottom with string, it will become Bottom->next*/
283 Bottom->string=malloc((_tcslen(string)+1)*sizeof(TCHAR));
284 _tcscpy(Bottom->string,string);
285
286 /*save Bottom value*/
287 tmp=Bottom;
288
289
290 /*create new void Bottom*/
291 Bottom=malloc(sizeof(HIST_ENTRY));
292 Bottom->next=tmp;
293 Bottom->prev=NULL;
294 Bottom->string=NULL;
295
296 tmp->prev=Bottom;
297
298 /*set new size*/
299 size++;
300
301 }
302
303
304
305 VOID History_move_to_bottom(VOID)
306 {
307 curr_ptr=Bottom;
308
309 }
310
311
312 VOID History (INT dir, LPTSTR commandline)
313 {
314
315 if(dir==0)
316 {
317 add_at_bottom(commandline);
318 curr_ptr=Bottom;
319 return;
320 }
321
322 if (size==0)
323 {
324 commandline[0]=_T('\0');
325 return;
326 }
327
328
329 if(dir<0)/*key up*/
330 {
331 if (curr_ptr->next==Top || curr_ptr==Top)
332 {
333 #ifdef WRAP_HISTORY
334 curr_ptr=Bottom;
335 #else
336 curr_ptr=Top;
337 commandline[0]=_T('\0');
338 return;
339 #endif
340 }
341
342
343 curr_ptr = curr_ptr->next;
344 if(curr_ptr->string)
345 _tcscpy(commandline,curr_ptr->string);
346
347 }
348
349
350
351
352
353 if(dir>0)
354 {
355
356 if (curr_ptr->prev==Bottom || curr_ptr==Bottom)
357 {
358 #ifdef WRAP_HISTORY
359 curr_ptr=Top;
360 #else
361 curr_ptr=Bottom;
362 commandline[0]=_T('\0');
363 return;
364 #endif
365 }
366
367 curr_ptr=curr_ptr->prev;
368 if(curr_ptr->string)
369 _tcscpy(commandline,curr_ptr->string);
370
371 }
372 }
373
374
375
376
377
378
379 #if 0
380
381 LPTSTR history = NULL; /*buffer to sotre all the lines*/
382 LPTSTR lines[MAXLINES]; /*array of pointers to each line(entry)*/
383 /*located in history buffer*/
384
385 INT curline = 0; /*the last line recalled by user*/
386 INT numlines = 0; /*number of entries, included the last*/
387 /*empty one*/
388
389 INT maxpos = 0; /*index of last byte of last entry*/
390
391
392
393 VOID History (INT dir, LPTSTR commandline)
394 {
395
396 INT count; /*used in for loops*/
397 INT length; /*used in the same loops of count*/
398 /*both to make room when is full
399 either history or lines*/
400
401 /*first time History is called allocate mem*/
402 if (!history)
403 {
404 history = malloc (history_size * sizeof (TCHAR));
405 lines[0] = history;
406 history[0] = 0;
407 }
408
409 if (dir > 0)
410 {
411 /* next command */
412 if (curline < numlines)
413 {
414 curline++;
415 }
416
417 if (curline == numlines)
418 {
419 commandline[0] = 0;
420 }
421 else
422 {
423 _tcscpy (commandline, lines[curline]);
424 }
425 }
426 else if (dir < 0)
427 {
428 /* prev command */
429 if (curline > 0)
430 {
431 curline--;
432 }
433
434 _tcscpy (commandline, lines[curline]);
435 }
436 else
437 {
438 /* add to history */
439 /* remove oldest string until there's enough room for next one */
440 /* strlen (commandline) must be less than history_size! */
441 while ((maxpos + (INT)_tcslen (commandline) + 1 > history_size) || (numlines >= MAXLINES))
442 {
443 length = _tcslen (lines[0]) + 1;
444
445 for (count = 0; count < maxpos && count + (lines[1] - lines[0]) < history_size; count++)
446 {
447 history[count] = history[count + length];
448 }
449
450 maxpos -= length;
451
452 for (count = 0; count <= numlines && count < MAXLINES; count++)
453 {
454 lines[count] = lines[count + 1] - length;
455 }
456
457 numlines--;
458 #ifdef DEBUG
459 ConOutPrintf (_T("Reduced size: %ld lines\n"), numlines);
460
461 for (count = 0; count < numlines; count++)
462 {
463 ConOutPrintf (_T("%d: %s\n"), count, lines[count]);
464 }
465 #endif
466 }
467
468 /*copy entry in the history bufer*/
469 _tcscpy (lines[numlines], commandline);
470 numlines++;
471
472 /*set last lines[numlines] pointer next the end of last, valid,
473 just setted entry (the two lines above)*/
474 lines[numlines] = lines[numlines - 1] + _tcslen (commandline) + 1;
475 maxpos += _tcslen (commandline) + 1;
476 /* last line, empty */
477
478 curline = numlines;
479 }
480
481 return;
482 }
483
484 #endif
485
486 #endif //#if 0