Sync with trunk r58687.
[reactos.git] / base / shell / 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)
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 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 = cmd_alloc(sizeof(HIST_ENTRY));
143 Bottom = cmd_alloc(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 cmd_free(Top);
165 cmd_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 TRACE ("del in " __FILE__ ": returning\n"
196 "item is 0x%08x (Bottom is0x%08x)\n",
197 item, Bottom);
198 return;
199 }
200
201
202
203 /*free string's mem*/
204 if (item->string)
205 cmd_free(item->string);
206
207 /*set links in prev and next item*/
208 item->next->prev=item->prev;
209 item->prev->next=item->next;
210
211 cmd_free(item);
212
213 size--;
214 }
215
216 static
217 VOID add_at_bottom(LPTSTR string)
218 {
219
220
221 LPHIST_ENTRY tmp;
222
223
224 /*delete first entry if maximum number of entries is reached*/
225 while(size>=max_size)
226 del(Top->prev);
227
228 while (_istspace(*string))
229 string++;
230
231 if (*string==_T('\0'))
232 return;
233
234
235 /*if new entry is the same than the last do not add it*/
236 if(size)
237 if(_tcscmp(string,Bottom->next->string)==0)
238 return;
239
240
241 /*fill bottom with string, it will become Bottom->next*/
242 Bottom->string=cmd_alloc((_tcslen(string)+1)*sizeof(TCHAR));
243 _tcscpy(Bottom->string,string);
244
245 /*save Bottom value*/
246 tmp=Bottom;
247
248
249 /*create new void Bottom*/
250 Bottom=cmd_alloc(sizeof(HIST_ENTRY));
251 Bottom->next=tmp;
252 Bottom->prev=NULL;
253 Bottom->string=NULL;
254
255 tmp->prev=Bottom;
256
257 /*set new size*/
258 size++;
259
260 }
261
262
263
264 VOID History_move_to_bottom(VOID)
265 {
266 curr_ptr=Bottom;
267
268 }
269
270 LPCTSTR PeekHistory(INT dir)
271 {
272 LPHIST_ENTRY entry = curr_ptr;
273
274 if (dir == 0)
275 return NULL;
276
277 if (dir < 0)
278 {
279 /* key up */
280 if (entry->next == Top || entry == Top)
281 {
282 #ifdef WRAP_HISTORY
283 entry = Bottom;
284 #else
285 return NULL;
286 #endif
287 }
288 entry = entry->next;
289 }
290 else
291 {
292 /* key down */
293 if (entry->next == Bottom || entry == Bottom)
294 {
295 #ifdef WRAP_HISTORY
296 entry = Top;
297 #else
298 return NULL;
299 #endif
300 }
301 entry = entry->prev;
302 }
303
304 return entry->string;
305 }
306
307 VOID History (INT dir, LPTSTR commandline)
308 {
309
310 if(dir==0)
311 {
312 add_at_bottom(commandline);
313 curr_ptr=Bottom;
314 return;
315 }
316
317 if (size==0)
318 {
319 commandline[0]=_T('\0');
320 return;
321 }
322
323
324 if(dir<0)/*key up*/
325 {
326 if (curr_ptr->next==Top || curr_ptr==Top)
327 {
328 #ifdef WRAP_HISTORY
329 curr_ptr=Bottom;
330 #else
331 curr_ptr=Top;
332 commandline[0]=_T('\0');
333 return;
334 #endif
335 }
336
337
338 curr_ptr = curr_ptr->next;
339 if(curr_ptr->string)
340 _tcscpy(commandline,curr_ptr->string);
341
342 }
343
344
345
346
347
348 if(dir>0)
349 {
350
351 if (curr_ptr->prev==Bottom || curr_ptr==Bottom)
352 {
353 #ifdef WRAP_HISTORY
354 curr_ptr=Top;
355 #else
356 curr_ptr=Bottom;
357 commandline[0]=_T('\0');
358 return;
359 #endif
360 }
361
362 curr_ptr=curr_ptr->prev;
363 if(curr_ptr->string)
364 _tcscpy(commandline,curr_ptr->string);
365
366 }
367 }
368
369 #endif //#if FEATURE_HISTORY