📄 list.c
字号:
// Search for an item in the list.
// For each item in the list, the SearchFcn is called with the item's data,
// and lParam.
// lParam is a pointer to a user-defined data block.
// Returns GE_TRUE if the search is successful. If GE_TRUE is returned,
// a pointer to the found item's data is returned in *ppData, and
// *pli is initialized to reference the found item.
// Returns GE_FALSE if the search is not successful.
geBoolean List_Search
(
List *pList,
List_SearchCallback SearchFcn,
void *lParam,
void **ppData,
ListIterator *pli
)
{
void *pData;
assert (pList != NULL);
assert (SearchFcn != NULL);
pData = List_GetFirst (pList, pli);
while (pData != NULL)
{
if (SearchFcn (pData, lParam) != GE_FALSE)
{
*ppData = pData;
return GE_TRUE;
}
pData = List_GetNext (pList, pli);
}
return GE_FALSE;
}
#ifdef LIST_TEST_CODE
#include <stdio.h>
#pragma warning (disable: 4100)
static void StringPrint (void *item, void *lParam)
{
char *s;
s = (char *)item;
printf ("%s\n", s);
}
#pragma warning (default: 4100)
static geBoolean StringSearchFcn (void *p1, void *lParam)
{
char *i1 = (char *)p1;
char *i2 = (char *)lParam;
return (strcmp (i1, i2) == 0) ? GE_TRUE : GE_FALSE;
}
static void StringDestroyFcn (void *p1)
{
assert (p1 != NULL);
free (p1);
}
/*
The test code reads list commands from an input file and applies those
commands to lists. The commands are in a sort of mini scripting language.
The commands take the form <command> <argument>, where <command> is
a 1- or 2-letter command (see below), and the argument is a string.
Commands are stored in the file one per line, with <command> being
the first two characters, followed by a space, and then the argument
which takes up the rest of the line. Blank lines and lines that start
with a semicolon are considered comments and are ignored by the
interpreter.
For example:
;create a new list
n
;append an item
a Hello, world
;print the list from front to back
pf
;destroy the list
d
The full list of commands is:
c Create a new list no argument
d Destroy a list no argument
a Append an item argument is the item to append
p Prepend an item argument is the item to prepend
s Search for an item argument is the item to search for
ib Insert before argument is the item to insert
ia Insert after argument is the item to insert
gf Get First no argument
gn Get Next no argument
gl Get Last no argument
gp Get Previous no argument
r Remove no argument
pc Print current no argument
pn Print # items no argument
pl Print list no argument
pb Print list reversed no argument
pr Print string to output
The script interpreter maintains the concept of a "current item,"
which is initialized by Search, GetFirst, or GetLast, and is
updated by GetNext and GetPrevious. This current item is an
implied argument in Insert before, Insert after, GetNext, GetPrevious,
and Remove.
*/
static geBoolean ParseCommand
(
char const *InputLine,
int LineNo,
List **ppList,
ListIterator *pCurItem,
char **ppCurData
)
{
short intcmd;
char *sarg;
geBoolean rslt;
if ((InputLine[0] == '\0') || (InputLine[0] == ';'))
{
// it's a comment line
return GE_TRUE;
}
if ((InputLine[1] == ' ') || (InputLine[1] == '\0') || (InputLine[1] == '\n'))
{
intcmd = InputLine[0];
}
else if ((InputLine[2] == ' ') || (InputLine[2] == '\0') || (InputLine[2] == '\n'))
{
short temp;
intcmd = *((short *)&InputLine[0]);
// swap the bytes
temp = (short)(intcmd & 0xff);
intcmd = (short)((intcmd >> 8) | (temp << 8));
}
else
{
printf ("Parse error on line %d\n", LineNo);
return GE_FALSE;
}
rslt = GE_TRUE;
switch (intcmd)
{
case 'c' :
if (*ppList != NULL)
{
puts ("Warning: Deleting old list.");
List_Destroy (ppList, StringDestroyFcn);
}
*ppList = List_Create ();
if (*ppList == NULL)
{
puts ("Error creating list");
rslt = GE_FALSE;
}
else
{
puts ("Created new list");
}
break;
case 'd' :
if (*ppList == NULL)
{
puts ("Warning: Trying to destroy NULL list.");
}
else
{
puts ("Destroy list");
List_Destroy (ppList, StringDestroyFcn);
}
break;
case 'a' :
sarg = strdup (&InputLine[2]);
if (sarg == NULL)
{
puts ("Error: no argument for append");
rslt = GE_FALSE;
}
else
{
if (List_Append (*ppList, sarg))
{
printf ("Append (%s)\n", sarg);
}
else
{
puts ("Error in append");
rslt = GE_FALSE;
}
}
break;
case 'p' :
sarg = strdup (&InputLine[2]);
if (sarg == NULL)
{
puts ("Error: no argument for prepend");
rslt = GE_FALSE;
}
else
{
if (List_Prepend (*ppList, sarg))
{
printf ("Prepend (%s)\n", sarg);
}
else
{
puts ("Error in Prepend");
rslt = GE_FALSE;
}
}
break;
case 's' :
sarg = strdup (&InputLine[2]);
if (sarg == NULL)
{
puts ("Error: no argument for search");
rslt = GE_FALSE;
}
else
{
geBoolean SrchRslt;
char *pData;
SrchRslt = List_Search (*ppList, StringSearchFcn, sarg, (void **)&pData, pCurItem);
if (SrchRslt)
{
printf ("Search: Found (%s). Data = (%s)\n", sarg, pData);
}
else
{
printf ("Search: Unable to find (%s)\n", sarg);
}
}
break;
case 'ib' :
sarg = strdup (&InputLine[3]);
if (sarg == NULL)
{
puts ("Error: no argument for insert before.");
rslt = GE_FALSE;
}
else
{
if (List_InsertBefore (*ppList, *pCurItem, sarg) != LIST_INVALID_NODE)
{
printf ("Insert (%s) before (%s).\n", sarg, (*pCurItem)->Data);
}
else
{
printf ("InsertBefore: error inserting (%s)\n", sarg);
rslt = GE_FALSE;
}
}
break;
case 'ia' :
sarg = strdup (&InputLine[3]);
if (sarg == NULL)
{
puts ("Error: no argument for insert after.");
rslt = GE_FALSE;
}
else
{
if (List_InsertAfter (*ppList, *pCurItem, sarg))
{
printf ("Insert (%s) after (%s).\n", sarg, (*pCurItem)->Data);
}
else
{
printf ("InsertAfter: error inserting (%s)\n", sarg);
rslt = GE_FALSE;
}
}
break;
case 'gf' :
puts ("Get First");
*ppCurData = List_GetFirst (*ppList, pCurItem);
break;
case 'gn' :
puts ("Get Next");
*ppCurData = List_GetNext (*ppList, pCurItem);
break;
case 'gl' :
puts ("Get Last");
*ppCurData = List_GetLast (*ppList, pCurItem);
break;
case 'gp' :
puts ("Get Previous");
*ppCurData = List_GetPrev (*ppList, pCurItem);
break;
case 'r' :
puts ("Remove");
List_Remove (*ppList, *pCurItem, StringDestroyFcn);
break;
case 'pc' :
if (*ppCurData == NULL)
{
puts ("No current item to print\n");
}
else
{
printf ("Print Current = (%s)\n", *ppCurData);
}
break;
case 'pn' :
printf ("NumItems = %d\n", List_GetNumItems (*ppList));
break;
case 'pl' :
puts ("Print list");
printf ("NumItems = %d\n", List_GetNumItems (*ppList));
puts ("----------");
List_ForEach (*ppList, StringPrint, NULL);
puts ("----------");
break;
case 'pb' :
{
char *MyData;
ListIterator li;
puts ("Print list backwards");
printf ("NumItems = %d\n", List_GetNumItems (*ppList));
puts ("--------------------");
MyData = List_GetLast (*ppList, &li);
while (MyData != NULL)
{
printf ("%s\n", MyData);
MyData = List_GetPrev (*ppList, &li);
}
puts ("--------------------");
break;
}
case 'pr' :
puts (&InputLine[3]);
break;
default :
printf ("Unknown command on line %d\n", LineNo);
rslt = GE_FALSE;
break;
}
if (!rslt)
{
printf ("Error on line %d\n", LineNo);
printf ("Line = (%s)\n", InputLine);
}
return rslt;
}
int main
(
int argc,
char *argv[]
)
{
List *pList;
ListIterator CurItem;
char *pCurrentData;
char *InputFilename;
FILE *infile;
int LineNo;
geBoolean rslt;
puts ("List test version 1.0");
puts ("---------------------");
if (argc != 2)
{
puts ("Usage is List <scriptname>");
puts ("See source for scripting information.");
return 0;
}
InputFilename = argv[1];
infile = fopen (InputFilename, "rt");
if (infile == NULL)
{
printf ("Can't open input file: '%s'\n", InputFilename);
return 0;
}
LineNo = 0;
pList = NULL;
CurItem = LIST_INVALID_NODE;
rslt = GE_TRUE;
while (rslt && !feof (infile))
{
char InputLine[256];
char *c;
if (fgets (InputLine, sizeof (InputLine), infile) == NULL)
{
// Why is this test necessary?
// Why doesn't feof return TRUE above?
if (!feof (infile))
{
puts ("Input error");
}
break;
}
// strip newline
c = strchr (InputLine, '\n');
if (c != NULL)
{
*c = '\0';
}
++LineNo;
rslt = ParseCommand (InputLine, LineNo, &pList, &CurItem, &pCurrentData);
}
if (pList != NULL)
{
List_Destroy (&pList, StringDestroyFcn);
}
fclose (infile);
return 0;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -