/* * HISTORY.C - command line history. * * * History: * * 14/01/95 (Tim Norman) * started. * * 08/08/95 (Matt Rains) * i have cleaned up the source code. changes now bring this source * into guidelines for recommended programming practice. * * 27-Jul-1998 (John P Price ) * added config.h include * * 25-Jan-1999 (Eric Kohl) * Cleanup! * Unicode and redirection safe! * * 25-Jan-1999 (Paolo Pantaleo ) * Added lots of comments (beginning studying the source) * Added command.com's F3 support (see cmdinput.c) * */ /* * HISTORY.C - command line history. Second version * * * History: * * 06/12/99 (Paolo Pantaleo ) * started. * */ #include "precomp.h" #ifdef FEATURE_HISTORY typedef struct tagHISTORY { struct tagHISTORY *prev; struct tagHISTORY *next; LPTSTR string; } HIST_ENTRY, * LPHIST_ENTRY; static INT size, max_size = 100; static LPHIST_ENTRY Top = NULL; static LPHIST_ENTRY Bottom = NULL; static LPHIST_ENTRY curr_ptr = NULL; VOID InitHistory(VOID); VOID History_move_to_bottom(VOID); VOID History(INT dir, LPTSTR commandline); VOID CleanHistory(VOID); VOID History_del_current_entry(LPTSTR str); /*service functions*/ static VOID del(LPHIST_ENTRY item); static VOID add_at_bottom(LPTSTR string); /*VOID add_before_last(LPTSTR string);*/ VOID set_size(INT new_size); INT CommandHistory(LPTSTR param) { LPTSTR tmp; INT tmp_int; LPHIST_ENTRY h_tmp; TCHAR szBuffer[2048]; tmp=_tcschr(param,_T('/')); if (tmp) { param=tmp; switch (_totupper(param[1])) { case _T('F'):/*delete history*/ CleanHistory();InitHistory(); break; case _T('R'):/*read history from standard in*/ for(;;) { ConInString(szBuffer,sizeof(szBuffer)/sizeof(TCHAR)); if (*szBuffer!=_T('\0')) History(0,szBuffer); else break; } break; case _T('A'):/*add an antry*/ History(0,param+2); break; case _T('S'):/*set history size*/ if ((tmp_int=_ttoi(param+2))) set_size(tmp_int); break; default: return 1; } } else { for (h_tmp = Top->prev; h_tmp != Bottom; h_tmp = h_tmp->prev) ConOutPrintf(_T("%s\n"), h_tmp->string); } return 0; } VOID set_size(INT new_size) { ASSERT(Top && Bottom); while (new_sizeprev); max_size=new_size; } VOID InitHistory(VOID) { size = 0; Top = cmd_alloc(sizeof(HIST_ENTRY)); if (!Top) { WARN("Cannot allocate memory for Top!\n"); return; } Bottom = cmd_alloc(sizeof(HIST_ENTRY)); if (!Bottom) { WARN("Cannot allocate memory for Bottom!\n"); cmd_free(Top); Top = NULL; return; } Top->prev = Bottom; Top->next = NULL; Top->string = NULL; Bottom->prev = NULL; Bottom->next = Top; Bottom->string = NULL; curr_ptr = Bottom; } VOID CleanHistory(VOID) { ASSERT(Top && Bottom); while (Bottom->next != Top) del(Bottom->next); cmd_free(Top); cmd_free(Bottom); } VOID History_del_current_entry(LPTSTR str) { LPHIST_ENTRY tmp; ASSERT(Top && Bottom); if (size == 0) return; if (curr_ptr == Bottom) curr_ptr = Bottom->next; if (curr_ptr == Top) curr_ptr = Top->prev; tmp = curr_ptr; curr_ptr = curr_ptr->prev; del(tmp); History(-1, str); } static VOID del(LPHIST_ENTRY item) { ASSERT(Top && Bottom); if (item==NULL || item==Top || item==Bottom) { TRACE ("del in " __FILE__ ": returning\n" "item is 0x%08x (Bottom is0x%08x)\n", item, Bottom); return; } /*free string's mem*/ if (item->string) cmd_free(item->string); /*set links in prev and next item*/ item->next->prev=item->prev; item->prev->next=item->next; cmd_free(item); size--; } static VOID add_at_bottom(LPTSTR string) { LPHIST_ENTRY tmp; ASSERT(Top && Bottom); /*delete first entry if maximum number of entries is reached*/ while (size>=max_size) del(Top->prev); while (_istspace(*string)) string++; if (*string==_T('\0')) return; /*if new entry is the same than the last do not add it*/ if (size) { if (_tcscmp(string,Bottom->next->string)==0) return; } /*create new empty Bottom*/ tmp = cmd_alloc(sizeof(HIST_ENTRY)); if (!tmp) { WARN("Cannot allocate memory for new Bottom!\n"); return; } /*fill old bottom with string, it will become new Bottom->next*/ Bottom->string = cmd_alloc((_tcslen(string)+1)*sizeof(TCHAR)); if (!Bottom->string) { WARN("Cannot allocate memory for Bottom->string!\n"); cmd_free(tmp); return; } _tcscpy(Bottom->string,string); tmp->next = Bottom; tmp->prev = NULL; tmp->string = NULL; Bottom->prev = tmp; /*save the new Bottom value*/ Bottom = tmp; /*set new size*/ size++; } VOID History_move_to_bottom(VOID) { ASSERT(Top && Bottom); curr_ptr = Bottom; } LPCTSTR PeekHistory(INT dir) { LPHIST_ENTRY entry = curr_ptr; ASSERT(Top && Bottom); if (dir == 0) return NULL; if (dir < 0) { /* key up */ if (entry->next == Top || entry == Top) { #ifdef WRAP_HISTORY entry = Bottom; #else return NULL; #endif } entry = entry->next; } else { /* key down */ if (entry->prev == Bottom || entry == Bottom) { #ifdef WRAP_HISTORY entry = Top; #else return NULL; #endif } entry = entry->prev; } return entry->string; } VOID History(INT dir, LPTSTR commandline) { ASSERT(Top && Bottom); if (dir==0) { add_at_bottom(commandline); curr_ptr = Bottom; return; } if (size==0) { commandline[0]=_T('\0'); return; } if (dir<0)/*key up*/ { if (curr_ptr->next==Top || curr_ptr==Top) { #ifdef WRAP_HISTORY curr_ptr = Bottom; #else curr_ptr = Top; commandline[0]=_T('\0'); return; #endif } curr_ptr = curr_ptr->next; if (curr_ptr->string) _tcscpy(commandline,curr_ptr->string); } if (dir>0) { if (curr_ptr->prev==Bottom || curr_ptr==Bottom) { #ifdef WRAP_HISTORY curr_ptr = Top; #else curr_ptr = Bottom; commandline[0]=_T('\0'); return; #endif } curr_ptr = curr_ptr->prev; if (curr_ptr->string) _tcscpy(commandline,curr_ptr->string); } } #endif //#if FEATURE_HISTORY