xref: /dflybsd-src/contrib/libedit/src/tokenizer.c (revision 12db70c8662d940c359926621f5dcef8a2365781)
1*12db70c8Szrj /*	$NetBSD: tokenizer.c,v 1.28 2016/04/11 18:56:31 christos Exp $	*/
232fe07f8SJohn Marino 
332fe07f8SJohn Marino /*-
432fe07f8SJohn Marino  * Copyright (c) 1992, 1993
532fe07f8SJohn Marino  *	The Regents of the University of California.  All rights reserved.
632fe07f8SJohn Marino  *
732fe07f8SJohn Marino  * This code is derived from software contributed to Berkeley by
832fe07f8SJohn Marino  * Christos Zoulas of Cornell University.
932fe07f8SJohn Marino  *
1032fe07f8SJohn Marino  * Redistribution and use in source and binary forms, with or without
1132fe07f8SJohn Marino  * modification, are permitted provided that the following conditions
1232fe07f8SJohn Marino  * are met:
1332fe07f8SJohn Marino  * 1. Redistributions of source code must retain the above copyright
1432fe07f8SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1532fe07f8SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1632fe07f8SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1732fe07f8SJohn Marino  *    documentation and/or other materials provided with the distribution.
1832fe07f8SJohn Marino  * 3. Neither the name of the University nor the names of its contributors
1932fe07f8SJohn Marino  *    may be used to endorse or promote products derived from this software
2032fe07f8SJohn Marino  *    without specific prior written permission.
2132fe07f8SJohn Marino  *
2232fe07f8SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2332fe07f8SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2432fe07f8SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2532fe07f8SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2632fe07f8SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2732fe07f8SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2832fe07f8SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2932fe07f8SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3032fe07f8SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3132fe07f8SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3232fe07f8SJohn Marino  * SUCH DAMAGE.
3332fe07f8SJohn Marino  */
3432fe07f8SJohn Marino 
3532fe07f8SJohn Marino #ifndef NARROWCHAR
3632fe07f8SJohn Marino #include "config.h"
3732fe07f8SJohn Marino #endif
3832fe07f8SJohn Marino 
3932fe07f8SJohn Marino #if !defined(lint) && !defined(SCCSID)
4032fe07f8SJohn Marino #if 0
4132fe07f8SJohn Marino static char sccsid[] = "@(#)tokenizer.c	8.1 (Berkeley) 6/4/93";
4232fe07f8SJohn Marino #else
43*12db70c8Szrj __RCSID("$NetBSD: tokenizer.c,v 1.28 2016/04/11 18:56:31 christos Exp $");
4432fe07f8SJohn Marino #endif
4532fe07f8SJohn Marino #endif /* not lint && not SCCSID */
4632fe07f8SJohn Marino 
4732fe07f8SJohn Marino /* We build this file twice, once as NARROW, once as WIDE. */
4832fe07f8SJohn Marino /*
4932fe07f8SJohn Marino  * tokenize.c: Bourne shell like tokenizer
5032fe07f8SJohn Marino  */
5132fe07f8SJohn Marino #include <stdlib.h>
52*12db70c8Szrj #include <string.h>
53*12db70c8Szrj 
5432fe07f8SJohn Marino #include "histedit.h"
5532fe07f8SJohn Marino 
5632fe07f8SJohn Marino typedef enum {
5732fe07f8SJohn Marino 	Q_none, Q_single, Q_double, Q_one, Q_doubleone
5832fe07f8SJohn Marino } quote_t;
5932fe07f8SJohn Marino 
6032fe07f8SJohn Marino #define	TOK_KEEP	1
6132fe07f8SJohn Marino #define	TOK_EAT		2
6232fe07f8SJohn Marino 
6332fe07f8SJohn Marino #define	WINCR		20
6432fe07f8SJohn Marino #define	AINCR		10
6532fe07f8SJohn Marino 
6632fe07f8SJohn Marino #define	IFS		STR("\t \n")
6732fe07f8SJohn Marino 
6832fe07f8SJohn Marino #define	tok_malloc(a)		malloc(a)
6932fe07f8SJohn Marino #define	tok_free(a)		free(a)
7032fe07f8SJohn Marino #define	tok_realloc(a, b)	realloc(a, b)
7132fe07f8SJohn Marino 
72*12db70c8Szrj #ifdef NARROWCHAR
73*12db70c8Szrj #define	Char			char
74*12db70c8Szrj #define	FUN(prefix, rest)	prefix ## _ ## rest
75*12db70c8Szrj #define	TYPE(type)		type
76*12db70c8Szrj #define	STR(x)			x
77*12db70c8Szrj #define	Strchr(s, c)		strchr(s, c)
78*12db70c8Szrj #define	tok_strdup(s)		strdup(s)
79*12db70c8Szrj #else
80*12db70c8Szrj #define	Char			wchar_t
81*12db70c8Szrj #define	FUN(prefix, rest)	prefix ## _w ## rest
82*12db70c8Szrj #define	TYPE(type)		type ## W
83*12db70c8Szrj #define	STR(x)			L ## x
84*12db70c8Szrj #define	Strchr(s, c)		wcschr(s, c)
85*12db70c8Szrj #define	tok_strdup(s)		wcsdup(s)
86*12db70c8Szrj #endif
8732fe07f8SJohn Marino 
TYPE(tokenizer)8832fe07f8SJohn Marino struct TYPE(tokenizer) {
8932fe07f8SJohn Marino 	Char	*ifs;		/* In field separator			 */
9032fe07f8SJohn Marino 	size_t	 argc, amax;	/* Current and maximum number of args	 */
9132fe07f8SJohn Marino 	Char   **argv;		/* Argument list			 */
9232fe07f8SJohn Marino 	Char	*wptr, *wmax;	/* Space and limit on the word buffer	 */
9332fe07f8SJohn Marino 	Char	*wstart;	/* Beginning of next word		 */
9432fe07f8SJohn Marino 	Char	*wspace;	/* Space of word buffer			 */
9532fe07f8SJohn Marino 	quote_t	 quote;		/* Quoting state			 */
9632fe07f8SJohn Marino 	int	 flags;		/* flags;				 */
9732fe07f8SJohn Marino };
9832fe07f8SJohn Marino 
9932fe07f8SJohn Marino 
100*12db70c8Szrj static void FUN(tok,finish)(TYPE(Tokenizer) *);
10132fe07f8SJohn Marino 
10232fe07f8SJohn Marino 
10332fe07f8SJohn Marino /* FUN(tok,finish)():
10432fe07f8SJohn Marino  *	Finish a word in the tokenizer.
10532fe07f8SJohn Marino  */
106*12db70c8Szrj static void
FUN(tok,finish)10732fe07f8SJohn Marino FUN(tok,finish)(TYPE(Tokenizer) *tok)
10832fe07f8SJohn Marino {
10932fe07f8SJohn Marino 
11032fe07f8SJohn Marino 	*tok->wptr = '\0';
11132fe07f8SJohn Marino 	if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) {
11232fe07f8SJohn Marino 		tok->argv[tok->argc++] = tok->wstart;
11332fe07f8SJohn Marino 		tok->argv[tok->argc] = NULL;
11432fe07f8SJohn Marino 		tok->wstart = ++tok->wptr;
11532fe07f8SJohn Marino 	}
11632fe07f8SJohn Marino 	tok->flags &= ~TOK_KEEP;
11732fe07f8SJohn Marino }
11832fe07f8SJohn Marino 
11932fe07f8SJohn Marino 
12032fe07f8SJohn Marino /* FUN(tok,init)():
12132fe07f8SJohn Marino  *	Initialize the tokenizer
12232fe07f8SJohn Marino  */
TYPE(Tokenizer)123*12db70c8Szrj TYPE(Tokenizer) *
12432fe07f8SJohn Marino FUN(tok,init)(const Char *ifs)
12532fe07f8SJohn Marino {
12632fe07f8SJohn Marino 	TYPE(Tokenizer) *tok = tok_malloc(sizeof(*tok));
12732fe07f8SJohn Marino 
12832fe07f8SJohn Marino 	if (tok == NULL)
12932fe07f8SJohn Marino 		return NULL;
13032fe07f8SJohn Marino 	tok->ifs = tok_strdup(ifs ? ifs : IFS);
13132fe07f8SJohn Marino 	if (tok->ifs == NULL) {
13232fe07f8SJohn Marino 		tok_free(tok);
13332fe07f8SJohn Marino 		return NULL;
13432fe07f8SJohn Marino 	}
13532fe07f8SJohn Marino 	tok->argc = 0;
13632fe07f8SJohn Marino 	tok->amax = AINCR;
13732fe07f8SJohn Marino 	tok->argv = tok_malloc(sizeof(*tok->argv) * tok->amax);
13832fe07f8SJohn Marino 	if (tok->argv == NULL) {
13932fe07f8SJohn Marino 		tok_free(tok->ifs);
14032fe07f8SJohn Marino 		tok_free(tok);
14132fe07f8SJohn Marino 		return NULL;
14232fe07f8SJohn Marino 	}
14332fe07f8SJohn Marino 	tok->argv[0] = NULL;
14432fe07f8SJohn Marino 	tok->wspace = tok_malloc(WINCR * sizeof(*tok->wspace));
14532fe07f8SJohn Marino 	if (tok->wspace == NULL) {
14632fe07f8SJohn Marino 		tok_free(tok->argv);
14732fe07f8SJohn Marino 		tok_free(tok->ifs);
14832fe07f8SJohn Marino 		tok_free(tok);
14932fe07f8SJohn Marino 		return NULL;
15032fe07f8SJohn Marino 	}
15132fe07f8SJohn Marino 	tok->wmax = tok->wspace + WINCR;
15232fe07f8SJohn Marino 	tok->wstart = tok->wspace;
15332fe07f8SJohn Marino 	tok->wptr = tok->wspace;
15432fe07f8SJohn Marino 	tok->flags = 0;
15532fe07f8SJohn Marino 	tok->quote = Q_none;
15632fe07f8SJohn Marino 
15732fe07f8SJohn Marino 	return tok;
15832fe07f8SJohn Marino }
15932fe07f8SJohn Marino 
16032fe07f8SJohn Marino 
16132fe07f8SJohn Marino /* FUN(tok,reset)():
16232fe07f8SJohn Marino  *	Reset the tokenizer
16332fe07f8SJohn Marino  */
164*12db70c8Szrj void
FUN(tok,reset)16532fe07f8SJohn Marino FUN(tok,reset)(TYPE(Tokenizer) *tok)
16632fe07f8SJohn Marino {
16732fe07f8SJohn Marino 
16832fe07f8SJohn Marino 	tok->argc = 0;
16932fe07f8SJohn Marino 	tok->wstart = tok->wspace;
17032fe07f8SJohn Marino 	tok->wptr = tok->wspace;
17132fe07f8SJohn Marino 	tok->flags = 0;
17232fe07f8SJohn Marino 	tok->quote = Q_none;
17332fe07f8SJohn Marino }
17432fe07f8SJohn Marino 
17532fe07f8SJohn Marino 
17632fe07f8SJohn Marino /* FUN(tok,end)():
17732fe07f8SJohn Marino  *	Clean up
17832fe07f8SJohn Marino  */
179*12db70c8Szrj void
FUN(tok,end)18032fe07f8SJohn Marino FUN(tok,end)(TYPE(Tokenizer) *tok)
18132fe07f8SJohn Marino {
18232fe07f8SJohn Marino 
18332fe07f8SJohn Marino 	tok_free(tok->ifs);
18432fe07f8SJohn Marino 	tok_free(tok->wspace);
18532fe07f8SJohn Marino 	tok_free(tok->argv);
18632fe07f8SJohn Marino 	tok_free(tok);
18732fe07f8SJohn Marino }
18832fe07f8SJohn Marino 
18932fe07f8SJohn Marino 
19032fe07f8SJohn Marino 
19132fe07f8SJohn Marino /* FUN(tok,line)():
19232fe07f8SJohn Marino  *	Bourne shell (sh(1)) like tokenizing
19332fe07f8SJohn Marino  *	Arguments:
19432fe07f8SJohn Marino  *		tok	current tokenizer state (setup with FUN(tok,init)())
19532fe07f8SJohn Marino  *		line	line to parse
19632fe07f8SJohn Marino  *	Returns:
19732fe07f8SJohn Marino  *		-1	Internal error
19832fe07f8SJohn Marino  *		 3	Quoted return
19932fe07f8SJohn Marino  *		 2	Unmatched double quote
20032fe07f8SJohn Marino  *		 1	Unmatched single quote
20132fe07f8SJohn Marino  *		 0	Ok
20232fe07f8SJohn Marino  *	Modifies (if return value is 0):
20332fe07f8SJohn Marino  *		argc	number of arguments
20432fe07f8SJohn Marino  *		argv	argument array
20532fe07f8SJohn Marino  *		cursorc	if !NULL, argv element containing cursor
20632fe07f8SJohn Marino  *		cursorv	if !NULL, offset in argv[cursorc] of cursor
20732fe07f8SJohn Marino  */
208*12db70c8Szrj int
FUN(tok,line)20932fe07f8SJohn Marino FUN(tok,line)(TYPE(Tokenizer) *tok, const TYPE(LineInfo) *line,
21032fe07f8SJohn Marino     int *argc, const Char ***argv, int *cursorc, int *cursoro)
21132fe07f8SJohn Marino {
21232fe07f8SJohn Marino 	const Char *ptr;
21332fe07f8SJohn Marino 	int cc, co;
21432fe07f8SJohn Marino 
21532fe07f8SJohn Marino 	cc = co = -1;
21632fe07f8SJohn Marino 	ptr = line->buffer;
21732fe07f8SJohn Marino 	for (ptr = line->buffer; ;ptr++) {
21832fe07f8SJohn Marino 		if (ptr >= line->lastchar)
21932fe07f8SJohn Marino 			ptr = STR("");
22032fe07f8SJohn Marino 		if (ptr == line->cursor) {
22132fe07f8SJohn Marino 			cc = (int)tok->argc;
22232fe07f8SJohn Marino 			co = (int)(tok->wptr - tok->wstart);
22332fe07f8SJohn Marino 		}
22432fe07f8SJohn Marino 		switch (*ptr) {
22532fe07f8SJohn Marino 		case '\'':
22632fe07f8SJohn Marino 			tok->flags |= TOK_KEEP;
22732fe07f8SJohn Marino 			tok->flags &= ~TOK_EAT;
22832fe07f8SJohn Marino 			switch (tok->quote) {
22932fe07f8SJohn Marino 			case Q_none:
23032fe07f8SJohn Marino 				tok->quote = Q_single;	/* Enter single quote
23132fe07f8SJohn Marino 							 * mode */
23232fe07f8SJohn Marino 				break;
23332fe07f8SJohn Marino 
23432fe07f8SJohn Marino 			case Q_single:	/* Exit single quote mode */
23532fe07f8SJohn Marino 				tok->quote = Q_none;
23632fe07f8SJohn Marino 				break;
23732fe07f8SJohn Marino 
23832fe07f8SJohn Marino 			case Q_one:	/* Quote this ' */
23932fe07f8SJohn Marino 				tok->quote = Q_none;
24032fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
24132fe07f8SJohn Marino 				break;
24232fe07f8SJohn Marino 
24332fe07f8SJohn Marino 			case Q_double:	/* Stay in double quote mode */
24432fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
24532fe07f8SJohn Marino 				break;
24632fe07f8SJohn Marino 
24732fe07f8SJohn Marino 			case Q_doubleone:	/* Quote this ' */
24832fe07f8SJohn Marino 				tok->quote = Q_double;
24932fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
25032fe07f8SJohn Marino 				break;
25132fe07f8SJohn Marino 
25232fe07f8SJohn Marino 			default:
25332fe07f8SJohn Marino 				return -1;
25432fe07f8SJohn Marino 			}
25532fe07f8SJohn Marino 			break;
25632fe07f8SJohn Marino 
25732fe07f8SJohn Marino 		case '"':
25832fe07f8SJohn Marino 			tok->flags &= ~TOK_EAT;
25932fe07f8SJohn Marino 			tok->flags |= TOK_KEEP;
26032fe07f8SJohn Marino 			switch (tok->quote) {
26132fe07f8SJohn Marino 			case Q_none:	/* Enter double quote mode */
26232fe07f8SJohn Marino 				tok->quote = Q_double;
26332fe07f8SJohn Marino 				break;
26432fe07f8SJohn Marino 
26532fe07f8SJohn Marino 			case Q_double:	/* Exit double quote mode */
26632fe07f8SJohn Marino 				tok->quote = Q_none;
26732fe07f8SJohn Marino 				break;
26832fe07f8SJohn Marino 
26932fe07f8SJohn Marino 			case Q_one:	/* Quote this " */
27032fe07f8SJohn Marino 				tok->quote = Q_none;
27132fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
27232fe07f8SJohn Marino 				break;
27332fe07f8SJohn Marino 
27432fe07f8SJohn Marino 			case Q_single:	/* Stay in single quote mode */
27532fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
27632fe07f8SJohn Marino 				break;
27732fe07f8SJohn Marino 
27832fe07f8SJohn Marino 			case Q_doubleone:	/* Quote this " */
27932fe07f8SJohn Marino 				tok->quote = Q_double;
28032fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
28132fe07f8SJohn Marino 				break;
28232fe07f8SJohn Marino 
28332fe07f8SJohn Marino 			default:
28432fe07f8SJohn Marino 				return -1;
28532fe07f8SJohn Marino 			}
28632fe07f8SJohn Marino 			break;
28732fe07f8SJohn Marino 
28832fe07f8SJohn Marino 		case '\\':
28932fe07f8SJohn Marino 			tok->flags |= TOK_KEEP;
29032fe07f8SJohn Marino 			tok->flags &= ~TOK_EAT;
29132fe07f8SJohn Marino 			switch (tok->quote) {
29232fe07f8SJohn Marino 			case Q_none:	/* Quote next character */
29332fe07f8SJohn Marino 				tok->quote = Q_one;
29432fe07f8SJohn Marino 				break;
29532fe07f8SJohn Marino 
29632fe07f8SJohn Marino 			case Q_double:	/* Quote next character */
29732fe07f8SJohn Marino 				tok->quote = Q_doubleone;
29832fe07f8SJohn Marino 				break;
29932fe07f8SJohn Marino 
30032fe07f8SJohn Marino 			case Q_one:	/* Quote this, restore state */
30132fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
30232fe07f8SJohn Marino 				tok->quote = Q_none;
30332fe07f8SJohn Marino 				break;
30432fe07f8SJohn Marino 
30532fe07f8SJohn Marino 			case Q_single:	/* Stay in single quote mode */
30632fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
30732fe07f8SJohn Marino 				break;
30832fe07f8SJohn Marino 
30932fe07f8SJohn Marino 			case Q_doubleone:	/* Quote this \ */
31032fe07f8SJohn Marino 				tok->quote = Q_double;
31132fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
31232fe07f8SJohn Marino 				break;
31332fe07f8SJohn Marino 
31432fe07f8SJohn Marino 			default:
31532fe07f8SJohn Marino 				return -1;
31632fe07f8SJohn Marino 			}
31732fe07f8SJohn Marino 			break;
31832fe07f8SJohn Marino 
31932fe07f8SJohn Marino 		case '\n':
32032fe07f8SJohn Marino 			tok->flags &= ~TOK_EAT;
32132fe07f8SJohn Marino 			switch (tok->quote) {
32232fe07f8SJohn Marino 			case Q_none:
32332fe07f8SJohn Marino 				goto tok_line_outok;
32432fe07f8SJohn Marino 
32532fe07f8SJohn Marino 			case Q_single:
32632fe07f8SJohn Marino 			case Q_double:
32732fe07f8SJohn Marino 				*tok->wptr++ = *ptr;	/* Add the return */
32832fe07f8SJohn Marino 				break;
32932fe07f8SJohn Marino 
33032fe07f8SJohn Marino 			case Q_doubleone:   /* Back to double, eat the '\n' */
33132fe07f8SJohn Marino 				tok->flags |= TOK_EAT;
33232fe07f8SJohn Marino 				tok->quote = Q_double;
33332fe07f8SJohn Marino 				break;
33432fe07f8SJohn Marino 
33532fe07f8SJohn Marino 			case Q_one:	/* No quote, more eat the '\n' */
33632fe07f8SJohn Marino 				tok->flags |= TOK_EAT;
33732fe07f8SJohn Marino 				tok->quote = Q_none;
33832fe07f8SJohn Marino 				break;
33932fe07f8SJohn Marino 
34032fe07f8SJohn Marino 			default:
34132fe07f8SJohn Marino 				return 0;
34232fe07f8SJohn Marino 			}
34332fe07f8SJohn Marino 			break;
34432fe07f8SJohn Marino 
34532fe07f8SJohn Marino 		case '\0':
34632fe07f8SJohn Marino 			switch (tok->quote) {
34732fe07f8SJohn Marino 			case Q_none:
34832fe07f8SJohn Marino 				/* Finish word and return */
34932fe07f8SJohn Marino 				if (tok->flags & TOK_EAT) {
35032fe07f8SJohn Marino 					tok->flags &= ~TOK_EAT;
35132fe07f8SJohn Marino 					return 3;
35232fe07f8SJohn Marino 				}
35332fe07f8SJohn Marino 				goto tok_line_outok;
35432fe07f8SJohn Marino 
35532fe07f8SJohn Marino 			case Q_single:
35632fe07f8SJohn Marino 				return 1;
35732fe07f8SJohn Marino 
35832fe07f8SJohn Marino 			case Q_double:
35932fe07f8SJohn Marino 				return 2;
36032fe07f8SJohn Marino 
36132fe07f8SJohn Marino 			case Q_doubleone:
36232fe07f8SJohn Marino 				tok->quote = Q_double;
36332fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
36432fe07f8SJohn Marino 				break;
36532fe07f8SJohn Marino 
36632fe07f8SJohn Marino 			case Q_one:
36732fe07f8SJohn Marino 				tok->quote = Q_none;
36832fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
36932fe07f8SJohn Marino 				break;
37032fe07f8SJohn Marino 
37132fe07f8SJohn Marino 			default:
37232fe07f8SJohn Marino 				return -1;
37332fe07f8SJohn Marino 			}
37432fe07f8SJohn Marino 			break;
37532fe07f8SJohn Marino 
37632fe07f8SJohn Marino 		default:
37732fe07f8SJohn Marino 			tok->flags &= ~TOK_EAT;
37832fe07f8SJohn Marino 			switch (tok->quote) {
37932fe07f8SJohn Marino 			case Q_none:
38032fe07f8SJohn Marino 				if (Strchr(tok->ifs, *ptr) != NULL)
38132fe07f8SJohn Marino 					FUN(tok,finish)(tok);
38232fe07f8SJohn Marino 				else
38332fe07f8SJohn Marino 					*tok->wptr++ = *ptr;
38432fe07f8SJohn Marino 				break;
38532fe07f8SJohn Marino 
38632fe07f8SJohn Marino 			case Q_single:
38732fe07f8SJohn Marino 			case Q_double:
38832fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
38932fe07f8SJohn Marino 				break;
39032fe07f8SJohn Marino 
39132fe07f8SJohn Marino 
39232fe07f8SJohn Marino 			case Q_doubleone:
39332fe07f8SJohn Marino 				*tok->wptr++ = '\\';
39432fe07f8SJohn Marino 				tok->quote = Q_double;
39532fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
39632fe07f8SJohn Marino 				break;
39732fe07f8SJohn Marino 
39832fe07f8SJohn Marino 			case Q_one:
39932fe07f8SJohn Marino 				tok->quote = Q_none;
40032fe07f8SJohn Marino 				*tok->wptr++ = *ptr;
40132fe07f8SJohn Marino 				break;
40232fe07f8SJohn Marino 
40332fe07f8SJohn Marino 			default:
40432fe07f8SJohn Marino 				return -1;
40532fe07f8SJohn Marino 
40632fe07f8SJohn Marino 			}
40732fe07f8SJohn Marino 			break;
40832fe07f8SJohn Marino 		}
40932fe07f8SJohn Marino 
41032fe07f8SJohn Marino 		if (tok->wptr >= tok->wmax - 4) {
41132fe07f8SJohn Marino 			size_t size = (size_t)(tok->wmax - tok->wspace + WINCR);
41232fe07f8SJohn Marino 			Char *s = tok_realloc(tok->wspace,
41332fe07f8SJohn Marino 			    size * sizeof(*s));
41432fe07f8SJohn Marino 			if (s == NULL)
41532fe07f8SJohn Marino 				return -1;
41632fe07f8SJohn Marino 
41732fe07f8SJohn Marino 			if (s != tok->wspace) {
41832fe07f8SJohn Marino 				size_t i;
41932fe07f8SJohn Marino 				for (i = 0; i < tok->argc; i++) {
42032fe07f8SJohn Marino 				    tok->argv[i] =
42132fe07f8SJohn Marino 					(tok->argv[i] - tok->wspace) + s;
42232fe07f8SJohn Marino 				}
42332fe07f8SJohn Marino 				tok->wptr = (tok->wptr - tok->wspace) + s;
42432fe07f8SJohn Marino 				tok->wstart = (tok->wstart - tok->wspace) + s;
42532fe07f8SJohn Marino 				tok->wspace = s;
42632fe07f8SJohn Marino 			}
42732fe07f8SJohn Marino 			tok->wmax = s + size;
42832fe07f8SJohn Marino 		}
42932fe07f8SJohn Marino 		if (tok->argc >= tok->amax - 4) {
43032fe07f8SJohn Marino 			Char **p;
43132fe07f8SJohn Marino 			tok->amax += AINCR;
43232fe07f8SJohn Marino 			p = tok_realloc(tok->argv, tok->amax * sizeof(*p));
433*12db70c8Szrj 			if (p == NULL) {
434*12db70c8Szrj 				tok->amax -= AINCR;
43532fe07f8SJohn Marino 				return -1;
436*12db70c8Szrj 			}
43732fe07f8SJohn Marino 			tok->argv = p;
43832fe07f8SJohn Marino 		}
43932fe07f8SJohn Marino 	}
44032fe07f8SJohn Marino  tok_line_outok:
44132fe07f8SJohn Marino 	if (cc == -1 && co == -1) {
44232fe07f8SJohn Marino 		cc = (int)tok->argc;
44332fe07f8SJohn Marino 		co = (int)(tok->wptr - tok->wstart);
44432fe07f8SJohn Marino 	}
44532fe07f8SJohn Marino 	if (cursorc != NULL)
44632fe07f8SJohn Marino 		*cursorc = cc;
44732fe07f8SJohn Marino 	if (cursoro != NULL)
44832fe07f8SJohn Marino 		*cursoro = co;
44932fe07f8SJohn Marino 	FUN(tok,finish)(tok);
45032fe07f8SJohn Marino 	*argv = (const Char **)tok->argv;
45132fe07f8SJohn Marino 	*argc = (int)tok->argc;
45232fe07f8SJohn Marino 	return 0;
45332fe07f8SJohn Marino }
45432fe07f8SJohn Marino 
45532fe07f8SJohn Marino /* FUN(tok,str)():
45632fe07f8SJohn Marino  *	Simpler version of tok_line, taking a NUL terminated line
45732fe07f8SJohn Marino  *	and splitting into words, ignoring cursor state.
45832fe07f8SJohn Marino  */
459*12db70c8Szrj int
FUN(tok,str)46032fe07f8SJohn Marino FUN(tok,str)(TYPE(Tokenizer) *tok, const Char *line, int *argc,
46132fe07f8SJohn Marino     const Char ***argv)
46232fe07f8SJohn Marino {
46332fe07f8SJohn Marino 	TYPE(LineInfo) li;
46432fe07f8SJohn Marino 
46532fe07f8SJohn Marino 	memset(&li, 0, sizeof(li));
46632fe07f8SJohn Marino 	li.buffer = line;
46732fe07f8SJohn Marino 	li.cursor = li.lastchar = Strchr(line, '\0');
468*12db70c8Szrj 	return FUN(tok,line)(tok, &li, argc, argv, NULL, NULL);
46932fe07f8SJohn Marino }
470