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 = NULL; 54 static LPHIST_ENTRY Bottom = NULL; 55 56 static LPHIST_ENTRY curr_ptr = NULL; 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 for(;;) 91 { 92 ConInString(szBuffer,sizeof(szBuffer)/sizeof(TCHAR)); 93 if (*szBuffer!=_T('\0')) 94 History(0,szBuffer); 95 else 96 break; 97 } 98 break; 99 100 case _T('A'):/*add an antry*/ 101 History(0,param+2); 102 break; 103 104 case _T('S'):/*set history size*/ 105 if ((tmp_int=_ttoi(param+2))) 106 set_size(tmp_int); 107 break; 108 109 default: 110 return 1; 111 } 112 } 113 else 114 { 115 for (h_tmp = Top->prev; h_tmp != Bottom; h_tmp = h_tmp->prev) 116 ConErrPuts(h_tmp->string); 117 } 118 return 0; 119 } 120 121 VOID set_size(INT new_size) 122 { 123 ASSERT(Top && Bottom); 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 if (!Top) 138 { 139 WARN("Cannot allocate memory for Top!\n"); 140 return; 141 } 142 Bottom = cmd_alloc(sizeof(HIST_ENTRY)); 143 if (!Bottom) 144 { 145 WARN("Cannot allocate memory for Bottom!\n"); 146 cmd_free(Top); 147 Top = NULL; 148 return; 149 } 150 151 Top->prev = Bottom; 152 Top->next = NULL; 153 Top->string = NULL; 154 155 Bottom->prev = NULL; 156 Bottom->next = Top; 157 Bottom->string = NULL; 158 159 curr_ptr = Bottom; 160 } 161 162 163 VOID CleanHistory(VOID) 164 { 165 ASSERT(Top && Bottom); 166 167 while (Bottom->next != Top) 168 del(Bottom->next); 169 170 cmd_free(Top); 171 cmd_free(Bottom); 172 } 173 174 175 VOID History_del_current_entry(LPTSTR str) 176 { 177 LPHIST_ENTRY tmp; 178 179 ASSERT(Top && Bottom); 180 181 if (size == 0) 182 return; 183 184 if (curr_ptr == Bottom) 185 curr_ptr = Bottom->next; 186 187 if (curr_ptr == Top) 188 curr_ptr = Top->prev; 189 190 191 tmp = curr_ptr; 192 curr_ptr = curr_ptr->prev; 193 del(tmp); 194 History(-1, str); 195 } 196 197 198 static 199 VOID del(LPHIST_ENTRY item) 200 { 201 ASSERT(Top && Bottom); 202 203 if (item==NULL || item==Top || item==Bottom) 204 { 205 TRACE ("del in " __FILE__ ": returning\n" 206 "item is 0x%08x (Bottom is0x%08x)\n", 207 item, Bottom); 208 return; 209 } 210 211 /*free string's mem*/ 212 if (item->string) 213 cmd_free(item->string); 214 215 /*set links in prev and next item*/ 216 item->next->prev=item->prev; 217 item->prev->next=item->next; 218 219 cmd_free(item); 220 221 size--; 222 } 223 224 static 225 VOID add_at_bottom(LPTSTR string) 226 { 227 LPHIST_ENTRY tmp; 228 229 ASSERT(Top && Bottom); 230 231 /*delete first entry if maximum number of entries is reached*/ 232 while (size>=max_size) 233 del(Top->prev); 234 235 while (_istspace(*string)) 236 string++; 237 238 if (*string==_T('\0')) 239 return; 240 241 /*if new entry is the same than the last do not add it*/ 242 if (size) 243 { 244 if (_tcscmp(string,Bottom->next->string)==0) 245 return; 246 } 247 248 /*create new empty Bottom*/ 249 tmp = cmd_alloc(sizeof(HIST_ENTRY)); 250 if (!tmp) 251 { 252 WARN("Cannot allocate memory for new Bottom!\n"); 253 return; 254 } 255 256 /*fill old bottom with string, it will become new Bottom->next*/ 257 Bottom->string = cmd_alloc((_tcslen(string)+1)*sizeof(TCHAR)); 258 if (!Bottom->string) 259 { 260 WARN("Cannot allocate memory for Bottom->string!\n"); 261 cmd_free(tmp); 262 return; 263 } 264 _tcscpy(Bottom->string,string); 265 266 tmp->next = Bottom; 267 tmp->prev = NULL; 268 tmp->string = NULL; 269 270 Bottom->prev = tmp; 271 272 /*save the new Bottom value*/ 273 Bottom = tmp; 274 275 /*set new size*/ 276 size++; 277 } 278 279 280 VOID History_move_to_bottom(VOID) 281 { 282 ASSERT(Top && Bottom); 283 284 curr_ptr = Bottom; 285 } 286 287 LPCTSTR PeekHistory(INT dir) 288 { 289 LPHIST_ENTRY entry = curr_ptr; 290 291 ASSERT(Top && Bottom); 292 293 if (dir == 0) 294 return NULL; 295 296 if (dir < 0) 297 { 298 /* key up */ 299 if (entry->next == Top || entry == Top) 300 { 301 #ifdef WRAP_HISTORY 302 entry = Bottom; 303 #else 304 return NULL; 305 #endif 306 } 307 entry = entry->next; 308 } 309 else 310 { 311 /* key down */ 312 if (entry->next == Bottom || entry == Bottom) 313 { 314 #ifdef WRAP_HISTORY 315 entry = Top; 316 #else 317 return NULL; 318 #endif 319 } 320 entry = entry->prev; 321 } 322 323 return entry->string; 324 } 325 326 VOID History(INT dir, LPTSTR commandline) 327 { 328 ASSERT(Top && Bottom); 329 330 if (dir==0) 331 { 332 add_at_bottom(commandline); 333 curr_ptr = Bottom; 334 return; 335 } 336 337 if (size==0) 338 { 339 commandline[0]=_T('\0'); 340 return; 341 } 342 343 if (dir<0)/*key up*/ 344 { 345 if (curr_ptr->next==Top || curr_ptr==Top) 346 { 347 #ifdef WRAP_HISTORY 348 curr_ptr = Bottom; 349 #else 350 curr_ptr = Top; 351 commandline[0]=_T('\0'); 352 return; 353 #endif 354 } 355 356 curr_ptr = curr_ptr->next; 357 if (curr_ptr->string) 358 _tcscpy(commandline,curr_ptr->string); 359 } 360 361 if (dir>0) 362 { 363 if (curr_ptr->prev==Bottom || curr_ptr==Bottom) 364 { 365 #ifdef WRAP_HISTORY 366 curr_ptr = Top; 367 #else 368 curr_ptr = Bottom; 369 commandline[0]=_T('\0'); 370 return; 371 #endif 372 } 373 374 curr_ptr = curr_ptr->prev; 375 if (curr_ptr->string) 376 _tcscpy(commandline,curr_ptr->string); 377 } 378 } 379 380 #endif //#if FEATURE_HISTORY 381