cosmopolitan/third_party/ctags/args.c

239 lines
5.9 KiB
C

/*
* $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/calls/calls.h"
#include "libc/str/str.h"
#include "third_party/ctags/args.h"
#include "third_party/ctags/debug.h"
#include "third_party/ctags/routines.h"
/*
* 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, &current->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: */