reactos/base/shell/cmd/history.c
Kyle Katarn ac2b2ef8c7
[CMD] HISTORY: Fix command output (missing linefeed) (#3205)
CORE-12603

Co-authored-by: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito@reactos.org>
2020-09-18 00:17:08 +02:00

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