mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 15:18:33 +00:00
381 lines
7.1 KiB
C
381 lines
7.1 KiB
C
/*
|
|
* 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 <linux-guru@gcfl.net>)
|
|
* added config.h include
|
|
*
|
|
* 25-Jan-1999 (Eric Kohl)
|
|
* Cleanup!
|
|
* Unicode and redirection safe!
|
|
*
|
|
* 25-Jan-1999 (Paolo Pantaleo <paolopan@freemail.it>)
|
|
* 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 <paolopan@freemail.it>)
|
|
* 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_size<size)
|
|
del(Top->prev);
|
|
|
|
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
|