1/*
2 * Copyright 1987, 1988 by MIT Student Information Processing Board
3 *
4 * For copyright info, see copyright.h.
5 */
6
7/*
8 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
9 * Use is subject to license terms.
10 */
11
12#include "ss_internal.h"
13#include "copyright.h"
14#include <errno.h>
15
16enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
17
18
19/*
20 * Solaris Kerberos:
21 * ss_parse has been modified slightly from the original in two ways.
22 * 1) A new parameter "quiet" has been added which is used to silence
23 *    error or warning messages.
24 * 2) ss_parse now returns an error status instead of argv - this is to
25 *    allow an error to be distinguished from no tokens when parsing an empty
26 *    string.
27 * Both of these changes allow ss_parse to be used during tab-completion.
28 */
29
30/*
31 * parse(line_ptr, argc_ptr)
32 *
33 * Function:
34 *      Parses line, dividing at whitespace, into tokens, returns
35 *      the "argc" and "argv" values.
36 * Arguments:
37 *      line_ptr (char *)
38 *              Pointer to text string to be parsed.
39 *      argc_ptr (int *)
40 *              Where to put the "argc" (number of tokens) value.
41 *      argv_ptr (char ***)
42 *              Where to put the series of pointers to parsed tokens.
43 * Returns:
44 *      error (0 - success, non-zero on failure)
45 */
46
47#define NEW_ARGV(old,n) (char **)realloc((char *)old,\
48					 (unsigned)(n+2)*sizeof(char*))
49
50int ss_parse (sci_idx, line_ptr, argc_ptr, argv_ptr, quiet)
51    int sci_idx;
52    register char *line_ptr;
53    int *argc_ptr;
54    char ***argv_ptr;
55    int quiet;
56{
57    register char **argv, *cp;
58    register int argc;
59    register enum parse_mode parse_mode;
60
61    argv = (char **) malloc (sizeof(char *));
62    if (argv == (char **)NULL) {
63	if (!quiet)
64	    ss_error(sci_idx, errno, "Can't allocate storage");
65	*argc_ptr = 0;
66	*argv_ptr = argv;
67	return(ENOMEM);
68    }
69    *argv = (char *)NULL;
70
71    argc = 0;
72
73    parse_mode = WHITESPACE;	/* flushing whitespace */
74    cp = line_ptr;		/* cp is for output */
75    while (1) {
76#ifdef DEBUG
77	{
78	    printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
79	}
80#endif
81	while (parse_mode == WHITESPACE) {
82	    if (*line_ptr == '\0')
83		goto end_of_line;
84	    if (*line_ptr == ' ' || *line_ptr == '\t') {
85		line_ptr++;
86		continue;
87	    }
88	    if (*line_ptr == '"') {
89		/* go to quoted-string mode */
90		parse_mode = QUOTED_STRING;
91		cp = line_ptr++;
92		argv = NEW_ARGV (argv, argc);
93		argv[argc++] = cp;
94		argv[argc] = NULL;
95	    }
96	    else {
97		/* random-token mode */
98		parse_mode = TOKEN;
99		cp = line_ptr;
100		argv = NEW_ARGV (argv, argc);
101		argv[argc++] = line_ptr;
102		argv[argc] = NULL;
103	    }
104	}
105	while (parse_mode == TOKEN) {
106	    if (*line_ptr == '\0') {
107		*cp++ = '\0';
108		goto end_of_line;
109	    }
110	    else if (*line_ptr == ' ' || *line_ptr == '\t') {
111		*cp++ = '\0';
112		line_ptr++;
113		parse_mode = WHITESPACE;
114	    }
115	    else if (*line_ptr == '"') {
116		line_ptr++;
117		parse_mode = QUOTED_STRING;
118	    }
119	    else {
120		*cp++ = *line_ptr++;
121	    }
122	}
123	while (parse_mode == QUOTED_STRING) {
124	    if (*line_ptr == '\0') {
125		if (!quiet)
126		    ss_error (sci_idx, 0,
127			"Unbalanced quotes in command line");
128		free (argv);
129		*argc_ptr = 0;
130		*argv_ptr = NULL;
131		return (-1);
132	    }
133	    else if (*line_ptr == '"') {
134		if (*++line_ptr == '"') {
135		    *cp++ = '"';
136		    line_ptr++;
137		}
138		else {
139		    parse_mode = TOKEN;
140		}
141	    }
142	    else {
143		*cp++ = *line_ptr++;
144	    }
145	}
146    }
147end_of_line:
148    *argc_ptr = argc;
149#ifdef DEBUG
150    {
151	int i;
152	printf ("argc = %d\n", argc);
153	for (i = 0; i <= argc; i++)
154	    printf ("\targv[%2d] = `%s'\n", i,
155		    argv[i] ? argv[i] : "<NULL>");
156    }
157#endif
158    *argv_ptr = argv;
159    return(0);
160}
161