parse.c revision e46c187aa6ee1ad6f38f0fb9c39da5e2bb6ceeb9
1/*
2 * Copyright 1987, 1988 by MIT Student Information Processing Board
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose is hereby granted, provided that
6 * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
7 * advertising or publicity pertaining to distribution of the software
8 * without specific, written prior permission.  M.I.T. and the
9 * M.I.T. S.I.P.B. make no representations about the suitability of
10 * this software for any purpose.  It is provided "as is" without
11 * express or implied warranty.
12 */
13
14#include "config.h"
15#ifdef HAS_STDLIB_H
16#include <stdlib.h>
17#endif
18#include <string.h>
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
22
23#include "ss_internal.h"
24
25enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
26
27/*
28 * parse(line_ptr, argc_ptr)
29 *
30 * Function:
31 *      Parses line, dividing at whitespace, into tokens, returns
32 *      the "argc" and "argv" values.
33 * Arguments:
34 *      line_ptr (char *)
35 *              Pointer to text string to be parsed.
36 *      argc_ptr (int *)
37 *              Where to put the "argc" (number of tokens) value.
38 * Returns:
39 *      argv (char **)
40 *              Series of pointers to parsed tokens.
41 */
42
43#define NEW_ARGV(old,n) (char **)realloc((char *)old,\
44					 (unsigned)(n+2)*sizeof(char*))
45
46char **ss_parse (sci_idx, line_ptr, argc_ptr)
47    int sci_idx;
48    register char *line_ptr;
49    int *argc_ptr;
50{
51    register char **argv, *cp;
52    register int argc;
53    register enum parse_mode parse_mode;
54
55    argv = (char **) malloc (sizeof(char *));
56    if (argv == (char **)NULL) {
57	ss_error(sci_idx, errno, "Can't allocate storage");
58	*argc_ptr = 0;
59	return(argv);
60    }
61    *argv = (char *)NULL;
62
63    argc = 0;
64
65    parse_mode = WHITESPACE;	/* flushing whitespace */
66    cp = line_ptr;		/* cp is for output */
67    while (1) {
68#ifdef DEBUG
69	{
70	    printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
71	}
72#endif
73	while (parse_mode == WHITESPACE) {
74	    if (*line_ptr == '\0')
75		goto end_of_line;
76	    if (*line_ptr == ' ' || *line_ptr == '\t') {
77		line_ptr++;
78		continue;
79	    }
80	    if (*line_ptr == '"') {
81		/* go to quoted-string mode */
82		parse_mode = QUOTED_STRING;
83		cp = line_ptr++;
84		argv = NEW_ARGV (argv, argc);
85		argv[argc++] = cp;
86		argv[argc] = NULL;
87	    }
88	    else {
89		/* random-token mode */
90		parse_mode = TOKEN;
91		cp = line_ptr;
92		argv = NEW_ARGV (argv, argc);
93		if (argv == NULL) {
94			*argc_ptr = errno;
95			return argv;
96		}
97		argv[argc++] = line_ptr;
98		argv[argc] = NULL;
99	    }
100	}
101	while (parse_mode == TOKEN) {
102	    if (*line_ptr == '\0') {
103		*cp++ = '\0';
104		goto end_of_line;
105	    }
106	    else if (*line_ptr == ' ' || *line_ptr == '\t') {
107		*cp++ = '\0';
108		line_ptr++;
109		parse_mode = WHITESPACE;
110	    }
111	    else if (*line_ptr == '"') {
112		line_ptr++;
113		parse_mode = QUOTED_STRING;
114	    }
115	    else {
116		*cp++ = *line_ptr++;
117	    }
118	}
119	while (parse_mode == QUOTED_STRING) {
120	    if (*line_ptr == '\0') {
121		ss_error (sci_idx, 0,
122			  "Unbalanced quotes in command line");
123		free (argv);
124		*argc_ptr = 0;
125		return NULL;
126	    }
127	    else if (*line_ptr == '"') {
128		if (*++line_ptr == '"') {
129		    *cp++ = '"';
130		    line_ptr++;
131		}
132		else {
133		    parse_mode = TOKEN;
134		}
135	    }
136	    else {
137		*cp++ = *line_ptr++;
138	    }
139	}
140    }
141end_of_line:
142    *argc_ptr = argc;
143#ifdef DEBUG
144    {
145	int i;
146	printf ("argc = %d\n", argc);
147	for (i = 0; i <= argc; i++)
148	    printf ("\targv[%2d] = `%s'\n", i,
149		    argv[i] ? argv[i] : "<NULL>");
150    }
151#endif
152    return(argv);
153}
154