1 /*
2 *   $Id: args.c 536 2007-06-02 06:09:00Z elliotth $
3 *
4 *   Copyright (c) 1999-2002, Darren Hiebert
5 *
6 *   This source code is released for free distribution under the terms of the
7 *   GNU General Public License.
8 *
9 *   This module contains functions for reading command line arguments.
10 */
11 
12 /*
13 *   INCLUDE FILES
14 */
15 #include "general.h"  /* must always come first */
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 
21 #include "args.h"
22 #include "debug.h"
23 #include "routines.h"
24 
25 /*
26 *   FUNCTION DEFINITIONS
27 */
28 
nextStringArg(const char ** const next)29 static char *nextStringArg (const char** const next)
30 {
31 	char* result = NULL;
32 	const char* start;
33 
34 	Assert (*next != NULL);
35 	for (start = *next  ;  isspace ((int) *start)  ;  ++start)
36 		;
37 	if (*start == '\0')
38 		*next = start;
39 	else
40 	{
41 		size_t length;
42 		const char* end;
43 
44 		for (end = start ;  *end != '\0'  &&  ! isspace ((int) *end)  ;  ++end)
45 			;
46 		length = end - start;
47 		Assert (length > 0);
48 		result = xMalloc (length + 1, char);
49 		strncpy (result, start, length);
50 		result [length] = '\0';
51 		*next = end;
52 	}
53 	return result;
54 }
55 
nextStringLine(const char ** const next)56 static char* nextStringLine (const char** const next)
57 {
58 	char* result = NULL;
59 	size_t length;
60 	const char* end;
61 
62 	Assert (*next != NULL);
63 	for (end = *next ;  *end != '\n'  &&  *end != '\0' ;  ++end)
64 		;
65 	length = end - *next;
66 	if (length > 0)
67 	{
68 		result = xMalloc (length + 1, char);
69 		strncpy (result, *next, length);
70 		result [length] = '\0';
71 	}
72 	if (*end == '\n')
73 		++end;
74 	else if (*end == '\r')
75 	{
76 		++end;
77 		if (*end == '\n')
78 			++end;
79 	}
80 	*next = end;
81 	return result;
82 }
83 
nextString(const Arguments * const current,const char ** const next)84 static char* nextString (const Arguments* const current, const char** const next)
85 {
86 	char* result;
87 	if (current->lineMode)
88 		result = nextStringLine (next);
89 	else
90 		result = nextStringArg (next);
91 	return result;
92 }
93 
nextFileArg(FILE * const fp)94 static char* nextFileArg (FILE* const fp)
95 {
96 	char* result = NULL;
97 	Assert (fp != NULL);
98 	if (! feof (fp))
99 	{
100 		vString* vs = vStringNew ();
101 		int c;
102 		do
103 			c = fgetc (fp);
104 		while (isspace (c));
105 
106 		if (c != EOF)
107 		{
108 			do
109 			{
110 				vStringPut (vs, c);
111 				c = fgetc (fp);
112 			} while (c != EOF  &&  ! isspace (c));
113 			vStringTerminate (vs);
114 			Assert (vStringLength (vs) > 0);
115 			result = xMalloc (vStringLength (vs) + 1, char);
116 			strcpy (result, vStringValue (vs));
117 		}
118 		vStringDelete (vs);
119 	}
120 	return result;
121 }
122 
nextFileLine(FILE * const fp)123 static char* nextFileLine (FILE* const fp)
124 {
125 	char* result = NULL;
126 	if (! feof (fp))
127 	{
128 		vString* vs = vStringNew ();
129 		int c;
130 
131 		Assert (fp != NULL);
132 		c = fgetc (fp);
133 		while (c != EOF)
134 		{
135 			if (c != '\n'  &&  c != '\r')
136 				vStringPut (vs, c);
137 			else if (vStringLength (vs) > 0)
138 				break;
139 			c = fgetc (fp);
140 		}
141 		if (c != EOF  ||  vStringLength (vs) > 0)
142 		{
143 			if (c == '\r')
144 			{
145 				c = fgetc (fp);
146 				if (c != '\n')
147 					c = ungetc (c, fp);
148 			}
149 			vStringTerminate (vs);
150 			vStringStripTrailing (vs);
151 			result = xMalloc (vStringLength (vs) + 1, char);
152 			strcpy (result, vStringValue (vs));
153 		}
154 		vStringDelete (vs);
155 	}
156 	return result;
157 }
158 
nextFileString(const Arguments * const current,FILE * const fp)159 static char* nextFileString (const Arguments* const current, FILE* const fp)
160 {
161 	char* result;
162 	if (current->lineMode)
163 		result = nextFileLine (fp);
164 	else
165 		result = nextFileArg (fp);
166 	return result;
167 }
168 
argNewFromString(const char * const string)169 extern Arguments* argNewFromString (const char* const string)
170 {
171 	Arguments* result = xMalloc (1, Arguments);
172 	memset (result, 0, sizeof (Arguments));
173 	result->type = ARG_STRING;
174 	result->u.stringArgs.string = string;
175 	result->u.stringArgs.item = string;
176 	result->u.stringArgs.next = string;
177 	result->item = nextString (result, &result->u.stringArgs.next);
178 	return result;
179 }
180 
argNewFromArgv(char * const * const argv)181 extern Arguments* argNewFromArgv (char* const* const argv)
182 {
183 	Arguments* result = xMalloc (1, Arguments);
184 	memset (result, 0, sizeof (Arguments));
185 	result->type = ARG_ARGV;
186 	result->u.argvArgs.argv = argv;
187 	result->u.argvArgs.item = result->u.argvArgs.argv;
188 	result->item = *result->u.argvArgs.item;
189 	return result;
190 }
191 
argNewFromFile(FILE * const fp)192 extern Arguments* argNewFromFile (FILE* const fp)
193 {
194 	Arguments* result = xMalloc (1, Arguments);
195 	memset (result, 0, sizeof (Arguments));
196 	result->type = ARG_FILE;
197 	result->u.fileArgs.fp = fp;
198 	result->item = nextFileString (result, result->u.fileArgs.fp);
199 	return result;
200 }
201 
argNewFromLineFile(FILE * const fp)202 extern Arguments* argNewFromLineFile (FILE* const fp)
203 {
204 	Arguments* result = xMalloc (1, Arguments);
205 	memset (result, 0, sizeof (Arguments));
206 	result->type = ARG_FILE;
207 	result->lineMode = TRUE;
208 	result->u.fileArgs.fp = fp;
209 	result->item = nextFileString (result, result->u.fileArgs.fp);
210 	return result;
211 }
212 
argItem(const Arguments * const current)213 extern char *argItem (const Arguments* const current)
214 {
215 	Assert (current != NULL);
216 	Assert (! argOff (current));
217 	return current->item;
218 }
219 
argOff(const Arguments * const current)220 extern boolean argOff (const Arguments* const current)
221 {
222 	Assert (current != NULL);
223 	return (boolean) (current->item == NULL);
224 }
225 
argSetWordMode(Arguments * const current)226 extern void argSetWordMode (Arguments* const current)
227 {
228 	Assert (current != NULL);
229 	current->lineMode = FALSE;
230 }
231 
argSetLineMode(Arguments * const current)232 extern void argSetLineMode (Arguments* const current)
233 {
234 	Assert (current != NULL);
235 	current->lineMode = TRUE;
236 }
237 
argForth(Arguments * const current)238 extern void argForth (Arguments* const current)
239 {
240 	Assert (current != NULL);
241 	Assert (! argOff (current));
242 	switch (current->type)
243 	{
244 		case ARG_STRING:
245 			if (current->item != NULL)
246 				eFree (current->item);
247 			current->u.stringArgs.item = current->u.stringArgs.next;
248 			current->item = nextString (current, &current->u.stringArgs.next);
249 			break;
250 		case ARG_ARGV:
251 			++current->u.argvArgs.item;
252 			current->item = *current->u.argvArgs.item;
253 			break;
254 		case ARG_FILE:
255 			if (current->item != NULL)
256 				eFree (current->item);
257 			current->item = nextFileString (current, current->u.fileArgs.fp);
258 			break;
259 		default:
260 			Assert ("Invalid argument type" == NULL);
261 			break;
262 	}
263 }
264 
argDelete(Arguments * const current)265 extern void argDelete (Arguments* const current)
266 {
267 	Assert (current != NULL);
268 	if (current->type ==  ARG_STRING  &&  current->item != NULL)
269 		eFree (current->item);
270 	memset (current, 0, sizeof (Arguments));
271 	eFree (current);
272 }
273 
274 /* vi:set tabstop=4 shiftwidth=4: */
275