parse.c revision 18a1444b4f1e6a0948fd38fa0de382d86cfe04de
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#ifdef HAS_STDLIB_H
15#include <stdlib.h>
16#endif
17#include <string.h>
18#ifdef HAVE_ERRNO_H
19#include <errno.h>
20#endif
21
22#include "ss_internal.h"
23
24enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
25
26/*
27 * parse(line_ptr, argc_ptr)
28 *
29 * Function:
30 *      Parses line, dividing at whitespace, into tokens, returns
31 *      the "argc" and "argv" values.
32 * Arguments:
33 *      line_ptr (char *)
34 *              Pointer to text string to be parsed.
35 *      argc_ptr (int *)
36 *              Where to put the "argc" (number of tokens) value.
37 * Returns:
38 *      argv (char **)
39 *              Series of pointers to parsed tokens.
40 */
41
42#define NEW_ARGV(old,n) (char **)realloc((char *)old,\
43					 (unsigned)(n+2)*sizeof(char*))
44
45char **ss_parse(int sci_idx, register char *line_ptr, int *argc_ptr)
46{
47    register char **argv, *cp;
48    register int argc;
49    register enum parse_mode parse_mode;
50
51    argv = (char **) malloc (sizeof(char *));
52    if (argv == (char **)NULL) {
53	ss_error(sci_idx, errno, "Can't allocate storage");
54	*argc_ptr = 0;
55	return(argv);
56    }
57    *argv = (char *)NULL;
58
59    argc = 0;
60
61    parse_mode = WHITESPACE;	/* flushing whitespace */
62    cp = line_ptr;		/* cp is for output */
63    while (1) {
64#ifdef DEBUG
65	{
66	    printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
67	}
68#endif
69	while (parse_mode == WHITESPACE) {
70	    if (*line_ptr == '\0')
71		goto end_of_line;
72	    if (*line_ptr == ' ' || *line_ptr == '\t') {
73		line_ptr++;
74		continue;
75	    }
76	    if (*line_ptr == '"') {
77		/* go to quoted-string mode */
78		parse_mode = QUOTED_STRING;
79		cp = line_ptr++;
80		argv = NEW_ARGV (argv, argc);
81		argv[argc++] = cp;
82		argv[argc] = NULL;
83	    }
84	    else {
85		/* random-token mode */
86		parse_mode = TOKEN;
87		cp = line_ptr;
88		argv = NEW_ARGV (argv, argc);
89		if (argv == NULL) {
90			*argc_ptr = errno;
91			return argv;
92		}
93		argv[argc++] = line_ptr;
94		argv[argc] = NULL;
95	    }
96	}
97	while (parse_mode == TOKEN) {
98	    if (*line_ptr == '\0') {
99		*cp++ = '\0';
100		goto end_of_line;
101	    }
102	    else if (*line_ptr == ' ' || *line_ptr == '\t') {
103		*cp++ = '\0';
104		line_ptr++;
105		parse_mode = WHITESPACE;
106	    }
107	    else if (*line_ptr == '"') {
108		line_ptr++;
109		parse_mode = QUOTED_STRING;
110	    }
111	    else {
112		*cp++ = *line_ptr++;
113	    }
114	}
115	while (parse_mode == QUOTED_STRING) {
116	    if (*line_ptr == '\0') {
117		ss_error (sci_idx, 0,
118			  "Unbalanced quotes in command line");
119		free (argv);
120		*argc_ptr = 0;
121		return NULL;
122	    }
123	    else if (*line_ptr == '"') {
124		if (*++line_ptr == '"') {
125		    *cp++ = '"';
126		    line_ptr++;
127		}
128		else {
129		    parse_mode = TOKEN;
130		}
131	    }
132	    else {
133		*cp++ = *line_ptr++;
134	    }
135	}
136    }
137end_of_line:
138    *argc_ptr = argc;
139#ifdef DEBUG
140    {
141	int i;
142	printf ("argc = %d\n", argc);
143	for (i = 0; i <= argc; i++)
144	    printf ("\targv[%2d] = `%s'\n", i,
145		    argv[i] ? argv[i] : "<NULL>");
146    }
147#endif
148    return(argv);
149}
150