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