1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
27 
28 #include <stdio.h>
29 #include <ctype.h>
30 
31 #define	TK_INIT		0
32 #define	TK_TOKEN	1
33 #define	TK_SKIPWHITE	2
34 #define	TK_QUOTED	3
35 
36 /*
37  * assumes quoted strings are delimited by white space (i.e sp
38  * "string" sp). Backslash can be used to quote a quote mark.
39  * quoted strings will have the quotes stripped.
40  */
41 
42 char *
_sa_get_token(char * string)43 _sa_get_token(char *string)
44 {
45 	static char *orig = NULL;
46 	static char *curp;
47 	char *ret;
48 	int state = TK_INIT;
49 	int c;
50 	int quotechar = 0;
51 
52 	if (string != orig || string == NULL) {
53 		orig = string;
54 		curp = string;
55 		if (string == NULL) {
56 			return (NULL);
57 		}
58 	}
59 	ret = curp;
60 	while ((c = *curp) != '\0') {
61 		switch (state) {
62 		case TK_SKIPWHITE:
63 		case TK_INIT:
64 			if (isspace(c)) {
65 				while (*curp && isspace(*curp))
66 					curp++;
67 				ret = curp;
68 			}
69 			if (c == '"' || c == '\'') {
70 				state = TK_QUOTED;
71 				curp++;
72 				ret = curp;
73 				quotechar = c; /* want to match for close */
74 			} else {
75 				state = TK_TOKEN;
76 			}
77 			break;
78 		case TK_TOKEN:
79 			switch (c) {
80 			case '\\':
81 				curp++;
82 				if (*curp) {
83 					curp++;
84 					break;
85 				}
86 				return (ret);
87 			default:
88 				if (*curp == '\0' || isspace(c)) {
89 					*curp++ = '\0';
90 					return (ret);
91 				}
92 				curp++;
93 				break;
94 			}
95 			break;
96 		case TK_QUOTED:
97 			switch (c) {
98 			case '\\':
99 				curp++;
100 				if (*curp) {
101 					curp++;
102 					break;
103 				}
104 				curp++;
105 				break;
106 			default:
107 				if (c == '\0' || c == quotechar) {
108 					*curp++ = '\0';
109 					return (ret);
110 				}
111 				curp++;
112 				break;
113 			}
114 			break;
115 		}
116 	}
117 	return (NULL);
118 }
119