/* * $Id: args.c 536 2007-06-02 06:09:00Z elliotth $ * * 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 for reading command line arguments. */ #include "third_party/ctags/general.h" /* must always come first */ /**/ #include "libc/str/str.h" #include "third_party/ctags/args.h" #include "third_party/ctags/debug.h" #include "third_party/ctags/routines.h" // clang-format off /* * FUNCTION DEFINITIONS */ static char *nextStringArg (const char** const next) { char* result = NULL; const char* start; Assert (*next != NULL); for (start = *next ; isspace ((int) *start) ; ++start) ; if (*start == '\0') *next = start; else { size_t length; const char* end; for (end = start ; *end != '\0' && ! isspace ((int) *end) ; ++end) ; length = end - start; Assert (length > 0); result = xMalloc (length + 1, char); strncpy (result, start, length); result [length] = '\0'; *next = end; } return result; } static char* nextStringLine (const char** const next) { char* result = NULL; size_t length; const char* end; Assert (*next != NULL); for (end = *next ; *end != '\n' && *end != '\0' ; ++end) ; length = end - *next; if (length > 0) { result = xMalloc (length + 1, char); strncpy (result, *next, length); result [length] = '\0'; } if (*end == '\n') ++end; else if (*end == '\r') { ++end; if (*end == '\n') ++end; } *next = end; return result; } static char* nextString (const Arguments* const current, const char** const next) { char* result; if (current->lineMode) result = nextStringLine (next); else result = nextStringArg (next); return result; } static char* nextFileArg (FILE* const fp) { char* result = NULL; Assert (fp != NULL); if (! feof (fp)) { vString* vs = vStringNew (); int c; do c = fgetc (fp); while (isspace (c)); if (c != EOF) { do { vStringPut (vs, c); c = fgetc (fp); } while (c != EOF && ! isspace (c)); vStringTerminate (vs); Assert (vStringLength (vs) > 0); result = xMalloc (vStringLength (vs) + 1, char); strcpy (result, vStringValue (vs)); } vStringDelete (vs); } return result; } static char* nextFileLine (FILE* const fp) { char* result = NULL; if (! feof (fp)) { vString* vs = vStringNew (); int c; Assert (fp != NULL); c = fgetc (fp); while (c != EOF) { if (c != '\n' && c != '\r') vStringPut (vs, c); else if (vStringLength (vs) > 0) break; c = fgetc (fp); } if (c != EOF || vStringLength (vs) > 0) { if (c == '\r') { c = fgetc (fp); if (c != '\n') c = ungetc (c, fp); } vStringTerminate (vs); vStringStripTrailing (vs); result = xMalloc (vStringLength (vs) + 1, char); strcpy (result, vStringValue (vs)); } vStringDelete (vs); } return result; } static char* nextFileString (const Arguments* const current, FILE* const fp) { char* result; if (current->lineMode) result = nextFileLine (fp); else result = nextFileArg (fp); return result; } extern Arguments* argNewFromString (const char* const string) { Arguments* result = xMalloc (1, Arguments); memset (result, 0, sizeof (Arguments)); result->type = ARG_STRING; result->u.stringArgs.string = string; result->u.stringArgs.item = string; result->u.stringArgs.next = string; result->item = nextString (result, &result->u.stringArgs.next); return result; } extern Arguments* argNewFromArgv (char* const* const argv) { Arguments* result = xMalloc (1, Arguments); memset (result, 0, sizeof (Arguments)); result->type = ARG_ARGV; result->u.argvArgs.argv = argv; result->u.argvArgs.item = result->u.argvArgs.argv; result->item = *result->u.argvArgs.item; return result; } extern Arguments* argNewFromFile (FILE* const fp) { Arguments* result = xMalloc (1, Arguments); memset (result, 0, sizeof (Arguments)); result->type = ARG_FILE; result->u.fileArgs.fp = fp; result->item = nextFileString (result, result->u.fileArgs.fp); return result; } extern Arguments* argNewFromLineFile (FILE* const fp) { Arguments* result = xMalloc (1, Arguments); memset (result, 0, sizeof (Arguments)); result->type = ARG_FILE; result->lineMode = TRUE; result->u.fileArgs.fp = fp; result->item = nextFileString (result, result->u.fileArgs.fp); return result; } extern char *argItem (const Arguments* const current) { Assert (current != NULL); Assert (! argOff (current)); return current->item; } extern boolean argOff (const Arguments* const current) { Assert (current != NULL); return (boolean) (current->item == NULL); } extern void argSetWordMode (Arguments* const current) { Assert (current != NULL); current->lineMode = FALSE; } extern void argSetLineMode (Arguments* const current) { Assert (current != NULL); current->lineMode = TRUE; } extern void argForth (Arguments* const current) { Assert (current != NULL); Assert (! argOff (current)); switch (current->type) { case ARG_STRING: if (current->item != NULL) eFree (current->item); current->u.stringArgs.item = current->u.stringArgs.next; current->item = nextString (current, ¤t->u.stringArgs.next); break; case ARG_ARGV: ++current->u.argvArgs.item; current->item = *current->u.argvArgs.item; break; case ARG_FILE: if (current->item != NULL) eFree (current->item); current->item = nextFileString (current, current->u.fileArgs.fp); break; default: Assert ("Invalid argument type" == NULL); break; } } extern void argDelete (Arguments* const current) { Assert (current != NULL); if (current->type == ARG_STRING && current->item != NULL) eFree (current->item); memset (current, 0, sizeof (Arguments)); eFree (current); } /* vi:set tabstop=4 shiftwidth=4: */