239 lines
5.9 KiB
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, ¤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: */
|