mirror of
https://github.com/jart/cosmopolitan.git
synced 2024-05-02 19:58:45 +00:00
284 lines
6.8 KiB
C
284 lines
6.8 KiB
C
// clang-format off
|
|
/*
|
|
* $Id: strlist.c 443 2006-05-30 04:37:13Z darren $
|
|
*
|
|
* Copyright (c) 1999-2002, Darren Hiebert
|
|
*
|
|
* This source code is released for free distribution under the terms of the
|
|
* GNU General Public License.
|
|
*
|
|
* This module contains functions managing resizable string lists.
|
|
*/
|
|
|
|
/*
|
|
* INCLUDE FILES
|
|
*/
|
|
#include "third_party/ctags/general.h" /* must always come first */
|
|
|
|
#include "libc/mem/alg.h"
|
|
#include "libc/str/str.h"
|
|
#ifdef HAVE_FNMATCH_H
|
|
#include "third_party/musl/fnmatch.h"
|
|
#endif
|
|
|
|
#include "third_party/ctags/debug.h"
|
|
#include "third_party/ctags/read.h"
|
|
#include "third_party/ctags/routines.h"
|
|
#include "third_party/ctags/strlist.h"
|
|
|
|
/*
|
|
* FUNCTION DEFINITIONS
|
|
*/
|
|
|
|
extern stringList *stringListNew (void)
|
|
{
|
|
stringList* const result = xMalloc (1, stringList);
|
|
result->max = 0;
|
|
result->count = 0;
|
|
result->list = NULL;
|
|
return result;
|
|
}
|
|
|
|
extern void stringListAdd (stringList *const current, vString *string)
|
|
{
|
|
enum { incrementalIncrease = 10 };
|
|
Assert (current != NULL);
|
|
if (current->list == NULL)
|
|
{
|
|
Assert (current->max == 0);
|
|
current->count = 0;
|
|
current->max = incrementalIncrease;
|
|
current->list = xMalloc (current->max, vString*);
|
|
}
|
|
else if (current->count == current->max)
|
|
{
|
|
current->max += incrementalIncrease;
|
|
current->list = xRealloc (current->list, current->max, vString*);
|
|
}
|
|
current->list [current->count++] = string;
|
|
}
|
|
|
|
extern void stringListRemoveLast (stringList *const current)
|
|
{
|
|
Assert (current != NULL);
|
|
Assert (current->count > 0);
|
|
--current->count;
|
|
current->list [current->count] = NULL;
|
|
}
|
|
|
|
/* Combine list `from' into `current', deleting `from' */
|
|
extern void stringListCombine (
|
|
stringList *const current, stringList *const from)
|
|
{
|
|
unsigned int i;
|
|
Assert (current != NULL);
|
|
Assert (from != NULL);
|
|
for (i = 0 ; i < from->count ; ++i)
|
|
{
|
|
stringListAdd (current, from->list [i]);
|
|
from->list [i] = NULL;
|
|
}
|
|
stringListDelete (from);
|
|
}
|
|
|
|
extern stringList* stringListNewFromArgv (const char* const* const argv)
|
|
{
|
|
stringList* const result = stringListNew ();
|
|
const char *const *p;
|
|
Assert (argv != NULL);
|
|
for (p = argv ; *p != NULL ; ++p)
|
|
stringListAdd (result, vStringNewInit (*p));
|
|
return result;
|
|
}
|
|
|
|
extern stringList* stringListNewFromFile (const char* const fileName)
|
|
{
|
|
stringList* result = NULL;
|
|
FILE* const fp = fopen (fileName, "r");
|
|
if (fp != NULL)
|
|
{
|
|
result = stringListNew ();
|
|
while (! feof (fp))
|
|
{
|
|
vString* const str = vStringNew ();
|
|
readLine (str, fp);
|
|
vStringStripTrailing (str);
|
|
if (vStringLength (str) > 0)
|
|
stringListAdd (result, str);
|
|
else
|
|
vStringDelete (str);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
extern unsigned int stringListCount (const stringList *const current)
|
|
{
|
|
Assert (current != NULL);
|
|
return current->count;
|
|
}
|
|
|
|
extern vString* stringListItem (
|
|
const stringList *const current, const unsigned int indx)
|
|
{
|
|
Assert (current != NULL);
|
|
return current->list [indx];
|
|
}
|
|
|
|
extern vString* stringListLast (const stringList *const current)
|
|
{
|
|
Assert (current != NULL);
|
|
Assert (current->count > 0);
|
|
return current->list [current->count - 1];
|
|
}
|
|
|
|
extern void stringListClear (stringList *const current)
|
|
{
|
|
unsigned int i;
|
|
Assert (current != NULL);
|
|
for (i = 0 ; i < current->count ; ++i)
|
|
{
|
|
vStringDelete (current->list [i]);
|
|
current->list [i] = NULL;
|
|
}
|
|
current->count = 0;
|
|
}
|
|
|
|
extern void stringListDelete (stringList *const current)
|
|
{
|
|
if (current != NULL)
|
|
{
|
|
if (current->list != NULL)
|
|
{
|
|
stringListClear (current);
|
|
eFree (current->list);
|
|
current->list = NULL;
|
|
}
|
|
current->max = 0;
|
|
current->count = 0;
|
|
eFree (current);
|
|
}
|
|
}
|
|
|
|
static boolean compareString (
|
|
const char *const string, vString *const itm)
|
|
{
|
|
return (boolean) (strcmp (string, vStringValue (itm)) == 0);
|
|
}
|
|
|
|
static boolean compareStringInsensitive (
|
|
const char *const string, vString *const itm)
|
|
{
|
|
return (boolean) (strcasecmp (string, vStringValue (itm)) == 0);
|
|
}
|
|
|
|
static int stringListIndex (
|
|
const stringList *const current,
|
|
const char *const string,
|
|
boolean (*test)(const char *s, vString *const vs))
|
|
{
|
|
int result = -1;
|
|
unsigned int i;
|
|
Assert (current != NULL);
|
|
Assert (string != NULL);
|
|
Assert (test != NULL);
|
|
for (i = 0 ; result == -1 && i < current->count ; ++i)
|
|
if ((*test)(string, current->list [i]))
|
|
result = i;
|
|
return result;
|
|
}
|
|
|
|
extern boolean stringListHas (
|
|
const stringList *const current, const char *const string)
|
|
{
|
|
boolean result = FALSE;
|
|
Assert (current != NULL);
|
|
result = stringListIndex (current, string, compareString) != -1;
|
|
return result;
|
|
}
|
|
|
|
extern boolean stringListHasInsensitive (
|
|
const stringList *const current, const char *const string)
|
|
{
|
|
boolean result = FALSE;
|
|
Assert (current != NULL);
|
|
Assert (string != NULL);
|
|
result = stringListIndex (current, string, compareStringInsensitive) != -1;
|
|
return result;
|
|
}
|
|
|
|
extern boolean stringListHasTest (
|
|
const stringList *const current, boolean (*test)(const char *s))
|
|
{
|
|
boolean result = FALSE;
|
|
unsigned int i;
|
|
Assert (current != NULL);
|
|
for (i = 0 ; ! result && i < current->count ; ++i)
|
|
result = (*test)(vStringValue (current->list [i]));
|
|
return result;
|
|
}
|
|
|
|
extern boolean stringListRemoveExtension (
|
|
stringList* const current, const char* const extension)
|
|
{
|
|
boolean result = FALSE;
|
|
int where;
|
|
#ifdef CASE_INSENSITIVE_FILENAMES
|
|
where = stringListIndex (current, extension, compareStringInsensitive);
|
|
#else
|
|
where = stringListIndex (current, extension, compareString);
|
|
#endif
|
|
if (where != -1)
|
|
{
|
|
memmove (current->list + where, current->list + where + 1,
|
|
(current->count - where) * sizeof (*current->list));
|
|
current->list [current->count - 1] = NULL;
|
|
--current->count;
|
|
result = TRUE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
extern boolean stringListExtensionMatched (
|
|
const stringList* const current, const char* const extension)
|
|
{
|
|
#ifdef CASE_INSENSITIVE_FILENAMES
|
|
return stringListHasInsensitive (current, extension);
|
|
#else
|
|
return stringListHas (current, extension);
|
|
#endif
|
|
}
|
|
|
|
static boolean fileNameMatched (
|
|
const vString* const vpattern, const char* const fileName)
|
|
{
|
|
const char* const pattern = vStringValue (vpattern);
|
|
#if defined (HAVE_FNMATCH)
|
|
return (boolean) (fnmatch (pattern, fileName, 0) == 0);
|
|
#elif defined (CASE_INSENSITIVE_FILENAMES)
|
|
return (boolean) (strcasecmp (pattern, fileName) == 0);
|
|
#else
|
|
return (boolean) (strcmp (pattern, fileName) == 0);
|
|
#endif
|
|
}
|
|
|
|
extern boolean stringListFileMatched (
|
|
const stringList* const current, const char* const fileName)
|
|
{
|
|
boolean result = FALSE;
|
|
unsigned int i;
|
|
for (i = 0 ; ! result && i < stringListCount (current) ; ++i)
|
|
result = fileNameMatched (stringListItem (current, i), fileName);
|
|
return result;
|
|
}
|
|
|
|
extern void stringListPrint (const stringList *const current)
|
|
{
|
|
unsigned int i;
|
|
Assert (current != NULL);
|
|
for (i = 0 ; i < current->count ; ++i)
|
|
printf ("%s%s", (i > 0) ? ", " : "", vStringValue (current->list [i]));
|
|
}
|
|
|
|
/* vi:set tabstop=4 shiftwidth=4: */
|