xref: /plan9/sys/src/cmd/gs/src/gsargs.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gsargs.c,v 1.9 2004/08/04 23:33:29 stefan Exp $ */
187dd7cddfSDavid du Colombier /* Command line argument list management */
197dd7cddfSDavid du Colombier #include "ctype_.h"
207dd7cddfSDavid du Colombier #include "stdio_.h"
217dd7cddfSDavid du Colombier #include "string_.h"
227dd7cddfSDavid du Colombier #include "gsexit.h"
237dd7cddfSDavid du Colombier #include "gsmemory.h"
247dd7cddfSDavid du Colombier #include "gsargs.h"
25*593dc095SDavid du Colombier #include "gserrors.h"
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier /* Initialize an arg list. */
287dd7cddfSDavid du Colombier void
arg_init(arg_list * pal,const char ** argv,int argc,FILE * (* arg_fopen)(const char * fname,void * fopen_data),void * fopen_data)297dd7cddfSDavid du Colombier arg_init(arg_list * pal, const char **argv, int argc,
30*593dc095SDavid du Colombier 	 FILE * (*arg_fopen) (const char *fname, void *fopen_data),
317dd7cddfSDavid du Colombier 	 void *fopen_data)
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier     pal->expand_ats = true;
347dd7cddfSDavid du Colombier     pal->arg_fopen = arg_fopen;
357dd7cddfSDavid du Colombier     pal->fopen_data = fopen_data;
367dd7cddfSDavid du Colombier     pal->argp = argv + 1;
377dd7cddfSDavid du Colombier     pal->argn = argc - 1;
387dd7cddfSDavid du Colombier     pal->depth = 0;
397dd7cddfSDavid du Colombier }
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier /* Push a string onto an arg list. */
423ff48bf5SDavid du Colombier int
arg_push_memory_string(arg_list * pal,char * str,gs_memory_t * mem)437dd7cddfSDavid du Colombier arg_push_memory_string(arg_list * pal, char *str, gs_memory_t * mem)
447dd7cddfSDavid du Colombier {
457dd7cddfSDavid du Colombier     arg_source *pas;
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier     if (pal->depth == arg_depth_max) {
487dd7cddfSDavid du Colombier 	lprintf("Too much nesting of @-files.\n");
493ff48bf5SDavid du Colombier 	return 1;
507dd7cddfSDavid du Colombier     }
517dd7cddfSDavid du Colombier     pas = &pal->sources[pal->depth];
527dd7cddfSDavid du Colombier     pas->is_file = false;
537dd7cddfSDavid du Colombier     pas->u.s.chars = str;
547dd7cddfSDavid du Colombier     pas->u.s.memory = mem;
557dd7cddfSDavid du Colombier     pas->u.s.str = str;
567dd7cddfSDavid du Colombier     pal->depth++;
573ff48bf5SDavid du Colombier     return 0;
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier /* Clean up an arg list. */
617dd7cddfSDavid du Colombier void
arg_finit(arg_list * pal)627dd7cddfSDavid du Colombier arg_finit(arg_list * pal)
637dd7cddfSDavid du Colombier {
647dd7cddfSDavid du Colombier     while (pal->depth) {
657dd7cddfSDavid du Colombier 	arg_source *pas = &pal->sources[--(pal->depth)];
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier 	if (pas->is_file)
687dd7cddfSDavid du Colombier 	    fclose(pas->u.file);
697dd7cddfSDavid du Colombier 	else if (pas->u.s.memory)
707dd7cddfSDavid du Colombier 	    gs_free_object(pas->u.s.memory, pas->u.s.chars, "arg_finit");
717dd7cddfSDavid du Colombier     }
727dd7cddfSDavid du Colombier }
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier /* Get the next arg from a list. */
757dd7cddfSDavid du Colombier /* Note that these are not copied to the heap. */
767dd7cddfSDavid du Colombier const char *
arg_next(arg_list * pal,int * code)773ff48bf5SDavid du Colombier arg_next(arg_list * pal, int *code)
787dd7cddfSDavid du Colombier {
797dd7cddfSDavid du Colombier     arg_source *pas;
807dd7cddfSDavid du Colombier     FILE *f;
817dd7cddfSDavid du Colombier     const char *astr = 0;	/* initialized only to pacify gcc */
827dd7cddfSDavid du Colombier     char *cstr;
837dd7cddfSDavid du Colombier     const char *result;
847dd7cddfSDavid du Colombier     int endc;
857dd7cddfSDavid du Colombier     int c, i;
867dd7cddfSDavid du Colombier     bool in_quote, eol;
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier   top:pas = &pal->sources[pal->depth - 1];
897dd7cddfSDavid du Colombier     if (pal->depth == 0) {
907dd7cddfSDavid du Colombier 	if (pal->argn <= 0)	/* all done */
917dd7cddfSDavid du Colombier 	    return 0;
927dd7cddfSDavid du Colombier 	pal->argn--;
937dd7cddfSDavid du Colombier 	result = *(pal->argp++);
947dd7cddfSDavid du Colombier 	goto at;
957dd7cddfSDavid du Colombier     }
967dd7cddfSDavid du Colombier     if (pas->is_file)
977dd7cddfSDavid du Colombier 	f = pas->u.file, endc = EOF;
987dd7cddfSDavid du Colombier     else
997dd7cddfSDavid du Colombier 	astr = pas->u.s.str, f = NULL, endc = 0;
1007dd7cddfSDavid du Colombier     result = cstr = pal->cstr;
1017dd7cddfSDavid du Colombier #define cfsgetc() (f == NULL ? (*astr ? *astr++ : 0) : fgetc(f))
1027dd7cddfSDavid du Colombier #define is_eol(c) (c == '\r' || c == '\n')
1037dd7cddfSDavid du Colombier     i = 0;
1047dd7cddfSDavid du Colombier     in_quote = false;
1057dd7cddfSDavid du Colombier     eol = true;
1067dd7cddfSDavid du Colombier     c = cfsgetc();
1077dd7cddfSDavid du Colombier     for (i = 0;;) {
1087dd7cddfSDavid du Colombier 	if (c == endc) {
1097dd7cddfSDavid du Colombier 	    if (in_quote) {
1107dd7cddfSDavid du Colombier 		cstr[i] = 0;
111*593dc095SDavid du Colombier 		errprintf("Unterminated quote in @-file: %s\n", cstr);
112*593dc095SDavid du Colombier 		*code = gs_error_Fatal;
1133ff48bf5SDavid du Colombier 		return NULL;
1147dd7cddfSDavid du Colombier 	    }
1157dd7cddfSDavid du Colombier 	    if (i == 0) {
1167dd7cddfSDavid du Colombier 		/* EOF before any argument characters. */
1177dd7cddfSDavid du Colombier 		if (f != NULL)
1187dd7cddfSDavid du Colombier 		    fclose(f);
1197dd7cddfSDavid du Colombier 		else if (pas->u.s.memory)
1207dd7cddfSDavid du Colombier 		    gs_free_object(pas->u.s.memory, pas->u.s.chars,
1217dd7cddfSDavid du Colombier 				   "arg_next");
1227dd7cddfSDavid du Colombier 		pal->depth--;
1237dd7cddfSDavid du Colombier 		goto top;
1247dd7cddfSDavid du Colombier 	    }
1257dd7cddfSDavid du Colombier 	    break;
1267dd7cddfSDavid du Colombier 	}
1277dd7cddfSDavid du Colombier 	/* c != endc */
1287dd7cddfSDavid du Colombier 	if (isspace(c)) {
1297dd7cddfSDavid du Colombier 	    if (i == 0) {
1307dd7cddfSDavid du Colombier 		c = cfsgetc();
1317dd7cddfSDavid du Colombier 		continue;
1327dd7cddfSDavid du Colombier 	    }
1337dd7cddfSDavid du Colombier 	    if (!in_quote)
1347dd7cddfSDavid du Colombier 		break;
1357dd7cddfSDavid du Colombier 	}
1367dd7cddfSDavid du Colombier 	/* c isn't leading or terminating whitespace. */
1377dd7cddfSDavid du Colombier 	if (c == '#' && eol) {
1387dd7cddfSDavid du Colombier 	    /* Skip a comment. */
1397dd7cddfSDavid du Colombier 	    do {
1407dd7cddfSDavid du Colombier 		c = cfsgetc();
1417dd7cddfSDavid du Colombier 	    } while (!(c == endc || is_eol(c)));
1427dd7cddfSDavid du Colombier 	    if (c == '\r')
1437dd7cddfSDavid du Colombier 		c = cfsgetc();
1447dd7cddfSDavid du Colombier 	    if (c == '\n')
1457dd7cddfSDavid du Colombier 		c = cfsgetc();
1467dd7cddfSDavid du Colombier 	    continue;
1477dd7cddfSDavid du Colombier 	}
1487dd7cddfSDavid du Colombier 	if (c == '\\') {
1497dd7cddfSDavid du Colombier 	    /* Check for \ followed by newline. */
1507dd7cddfSDavid du Colombier 	    c = cfsgetc();
1517dd7cddfSDavid du Colombier 	    if (is_eol(c)) {
1527dd7cddfSDavid du Colombier 		if (c == '\r')
1537dd7cddfSDavid du Colombier 		    c = cfsgetc();
1547dd7cddfSDavid du Colombier 		if (c == '\n')
1557dd7cddfSDavid du Colombier 		    c = cfsgetc();
1567dd7cddfSDavid du Colombier 		eol = true;
1577dd7cddfSDavid du Colombier 		continue;
1587dd7cddfSDavid du Colombier 	    }
1597dd7cddfSDavid du Colombier 	    /* \ anywhere else is treated as a printing character. */
1607dd7cddfSDavid du Colombier 	    /* This is different from the Unix shells. */
1617dd7cddfSDavid du Colombier 	    if (i == arg_str_max - 1) {
1627dd7cddfSDavid du Colombier 		cstr[i] = 0;
163*593dc095SDavid du Colombier 		errprintf("Command too long: %s\n", cstr);
164*593dc095SDavid du Colombier 		*code = gs_error_Fatal;
1653ff48bf5SDavid du Colombier 		return NULL;
1667dd7cddfSDavid du Colombier 	    }
1677dd7cddfSDavid du Colombier 	    cstr[i++] = '\\';
1687dd7cddfSDavid du Colombier 	    eol = false;
1697dd7cddfSDavid du Colombier 	    continue;
1707dd7cddfSDavid du Colombier 	}
1717dd7cddfSDavid du Colombier 	/* c will become part of the argument */
1727dd7cddfSDavid du Colombier 	if (i == arg_str_max - 1) {
1737dd7cddfSDavid du Colombier 	    cstr[i] = 0;
174*593dc095SDavid du Colombier 	    errprintf("Command too long: %s\n", cstr);
175*593dc095SDavid du Colombier 	    *code = gs_error_Fatal;
1763ff48bf5SDavid du Colombier 	    return NULL;
1777dd7cddfSDavid du Colombier 	}
1787dd7cddfSDavid du Colombier 	/* If input is coming from an @-file, allow quotes */
1797dd7cddfSDavid du Colombier 	/* to protect whitespace. */
1807dd7cddfSDavid du Colombier 	if (c == '"' && f != NULL)
1817dd7cddfSDavid du Colombier 	    in_quote = !in_quote;
1827dd7cddfSDavid du Colombier 	else
1837dd7cddfSDavid du Colombier 	    cstr[i++] = c;
1847dd7cddfSDavid du Colombier 	eol = is_eol(c);
1857dd7cddfSDavid du Colombier 	c = cfsgetc();
1867dd7cddfSDavid du Colombier     }
1877dd7cddfSDavid du Colombier     cstr[i] = 0;
1887dd7cddfSDavid du Colombier     if (f == NULL)
1897dd7cddfSDavid du Colombier 	pas->u.s.str = astr;
1907dd7cddfSDavid du Colombier   at:if (pal->expand_ats && result[0] == '@') {
1917dd7cddfSDavid du Colombier 	if (pal->depth == arg_depth_max) {
1927dd7cddfSDavid du Colombier 	    lprintf("Too much nesting of @-files.\n");
193*593dc095SDavid du Colombier 	    *code = gs_error_Fatal;
1943ff48bf5SDavid du Colombier 	    return NULL;
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier 	result++;		/* skip @ */
1977dd7cddfSDavid du Colombier 	f = (*pal->arg_fopen) (result, pal->fopen_data);
1987dd7cddfSDavid du Colombier 	if (f == NULL) {
199*593dc095SDavid du Colombier 	    errprintf("Unable to open command line file %s\n", result);
200*593dc095SDavid du Colombier 	    *code = gs_error_Fatal;
2013ff48bf5SDavid du Colombier 	    return NULL;
2027dd7cddfSDavid du Colombier 	}
2037dd7cddfSDavid du Colombier 	pal->depth++;
2047dd7cddfSDavid du Colombier 	pas++;
2057dd7cddfSDavid du Colombier 	pas->is_file = true;
2067dd7cddfSDavid du Colombier 	pas->u.file = f;
2077dd7cddfSDavid du Colombier 	goto top;
2087dd7cddfSDavid du Colombier     }
2097dd7cddfSDavid du Colombier     return result;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier /* Copy an argument string to the heap. */
2137dd7cddfSDavid du Colombier char *
arg_copy(const char * str,gs_memory_t * mem)2147dd7cddfSDavid du Colombier arg_copy(const char *str, gs_memory_t * mem)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier     char *sstr = (char *)gs_alloc_bytes(mem, strlen(str) + 1, "arg_copy");
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier     if (sstr == 0) {
2197dd7cddfSDavid du Colombier 	lprintf("Out of memory!\n");
2203ff48bf5SDavid du Colombier 	return NULL;
2217dd7cddfSDavid du Colombier     }
2227dd7cddfSDavid du Colombier     strcpy(sstr, str);
2237dd7cddfSDavid du Colombier     return sstr;
2247dd7cddfSDavid du Colombier }
225