Sync with trunk.
[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, max_size=100;
52
53 static LPHIST_ENTRY Top;
54 static LPHIST_ENTRY Bottom;
55
56 static LPHIST_ENTRY curr_ptr=0;
57
58 VOID InitHistory(VOID);
59 VOID History_move_to_bottom(VOID);
60 VOID History (INT dir, LPTSTR commandline);
61 VOID CleanHistory(VOID);
62 VOID History_del_current_entry(LPTSTR str);
63
64 /*service functions*/
65 static VOID del(LPHIST_ENTRY item);
66 static VOID add_at_bottom(LPTSTR string);
67 /*VOID add_before_last(LPTSTR string);*/
68 VOID set_size(INT new_size);
69
70
71 INT CommandHistory (LPTSTR param)
72 {
73 LPTSTR tmp;
74 INT tmp_int;
75 LPHIST_ENTRY h_tmp;
76 TCHAR szBuffer[2048];
77
78 tmp=_tcschr(param,_T('/'));
79
80 if (tmp)
81 {
82 param=tmp;
83 switch (_totupper(param[1]))
84 {
85 case _T('F'):/*delete history*/
86 CleanHistory();InitHistory();
87 break;
88
89 case _T('R'):/*read history from standard in*/
90 //hIn=GetStdHandle (STD_INPUT_HANDLE);
91
92 for(;;)
93 {
94 ConInString(szBuffer,sizeof(szBuffer)/sizeof(TCHAR));
95 if (*szBuffer!=_T('\0'))
96 History(0,szBuffer);
97 else
98 break;
99 }
100 break;
101
102 case _T('A'):/*add an antry*/
103 History(0,param+2);
104 break;
105
106 case _T('S'):/*set history size*/
107 if ((tmp_int=_ttoi(param+2)))
108 set_size(tmp_int);
109 break;
110
111 default:
112 return 1;
113 }
114 }
115 else
116 {
117 for (h_tmp = Top->prev; h_tmp != Bottom; h_tmp = h_tmp->prev)
118 ConErrPuts(h_tmp->string);
119 }
120 return 0;
121 }
122
123 VOID set_size(INT new_size)
124 {
125 while (new_size<size)
126 del(Top->prev);
127
128 max_size=new_size;
129 }
130
131
132 VOID InitHistory(VOID)
133 {
134 size=0;
135
136 Top = cmd_alloc(sizeof(HIST_ENTRY));
137 Bottom = cmd_alloc(sizeof(HIST_ENTRY));
138
139 Top->prev = Bottom;
140 Top->next = NULL;
141 Top->string = NULL;
142
143 Bottom->prev = NULL;
144 Bottom->next = Top;
145 Bottom->string = NULL;
146
147 curr_ptr=Bottom;
148 }
149
150
151 VOID CleanHistory(VOID)
152 {
153 while (Bottom->next!=Top)
154 del(Bottom->next);
155
156 cmd_free(Top);
157 cmd_free(Bottom);
158 }
159
160
161 VOID History_del_current_entry(LPTSTR str)
162 {
163 LPHIST_ENTRY tmp;
164
165 if (size == 0)
166 return;
167
168 if (curr_ptr == Bottom)
169 curr_ptr=Bottom->next;
170
171 if (curr_ptr == Top)
172 curr_ptr=Top->prev;
173
174
175 tmp = curr_ptr;
176 curr_ptr = curr_ptr->prev;
177 del(tmp);
178 History(-1, str);
179 }
180
181
182 static
183 VOID del(LPHIST_ENTRY item)
184 {
185 if (item==NULL || item==Top || item==Bottom)
186 {
187 TRACE ("del in " __FILE__ ": returning\n"
188 "item is 0x%08x (Bottom is0x%08x)\n",
189 item, Bottom);
190 return;
191 }
192
193 /*free string's mem*/
194 if (item->string)
195 cmd_free(item->string);
196
197 /*set links in prev and next item*/
198 item->next->prev=item->prev;
199 item->prev->next=item->next;
200
201 cmd_free(item);
202
203 size--;
204 }
205
206 static
207 VOID add_at_bottom(LPTSTR string)
208 {
209 LPHIST_ENTRY tmp;
210
211 /*delete first entry if maximum number of entries is reached*/
212 while(size>=max_size)
213 del(Top->prev);
214
215 while (_istspace(*string))
216 string++;
217
218 if (*string==_T('\0'))
219 return;
220
221 /*if new entry is the same than the last do not add it*/
222 if (size)
223 if (_tcscmp(string,Bottom->next->string)==0)
224 return;
225
226 /*fill bottom with string, it will become Bottom->next*/
227 Bottom->string=cmd_alloc((_tcslen(string)+1)*sizeof(TCHAR));
228 _tcscpy(Bottom->string,string);
229
230 /*save Bottom value*/
231 tmp=Bottom;
232
233 /*create new void Bottom*/
234 Bottom=cmd_alloc(sizeof(HIST_ENTRY));
235 Bottom->next=tmp;
236 Bottom->prev=NULL;
237 Bottom->string=NULL;
238
239 tmp->prev=Bottom;
240
241 /*set new size*/
242 size++;
243 }
244
245
246 VOID History_move_to_bottom(VOID)
247 {
248 curr_ptr=Bottom;
249 }
250
251 LPCTSTR PeekHistory(INT dir)
252 {
253 LPHIST_ENTRY entry = curr_ptr;
254
255 if (dir == 0)
256 return NULL;
257
258 if (dir < 0)
259 {
260 /* key up */
261 if (entry->next == Top || entry == Top)
262 {
263 #ifdef WRAP_HISTORY
264 entry = Bottom;
265 #else
266 return NULL;
267 #endif
268 }
269 entry = entry->next;
270 }
271 else
272 {
273 /* key down */
274 if (entry->next == Bottom || entry == Bottom)
275 {
276 #ifdef WRAP_HISTORY
277 entry = Top;
278 #else
279 return NULL;
280 #endif
281 }
282 entry = entry->prev;
283 }
284
285 return entry->string;
286 }
287
288 VOID History (INT dir, LPTSTR commandline)
289 {
290 if (dir==0)
291 {
292 add_at_bottom(commandline);
293 curr_ptr=Bottom;
294 return;
295 }
296
297 if (size==0)
298 {
299 commandline[0]=_T('\0');
300 return;
301 }
302
303 if (dir<0)/*key up*/
304 {
305 if (curr_ptr->next==Top || curr_ptr==Top)
306 {
307 #ifdef WRAP_HISTORY
308 curr_ptr=Bottom;
309 #else
310 curr_ptr=Top;
311 commandline[0]=_T('\0');
312 return;
313 #endif
314 }
315
316 curr_ptr = curr_ptr->next;
317 if (curr_ptr->string)
318 _tcscpy(commandline,curr_ptr->string);
319 }
320
321 if (dir>0)
322 {
323 if (curr_ptr->prev==Bottom || curr_ptr==Bottom)
324 {
325 #ifdef WRAP_HISTORY
326 curr_ptr=Top;
327 #else
328 curr_ptr=Bottom;
329 commandline[0]=_T('\0');
330 return;
331 #endif
332 }
333
334 curr_ptr=curr_ptr->prev;
335 if (curr_ptr->string)
336 _tcscpy(commandline,curr_ptr->string);
337 }
338 }
339
340 #endif //#if FEATURE_HISTORY