xref: /illumos-gate/usr/src/common/util/getoptstr.c (revision b10f758d69dd151326d3859af7e1d857ec9a6355)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1992-1996,2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /*
32  * This file contains getoptstr(), which is getopt() for strings of arguments
33  * (not arrays of strings).  It is used by the bootloader ({*fs,inet}boot) and
34  * the kernel to process argument strings.
35  */
36 
37 
38 #include "getoptstr.h"
39 #include <sys/null.h>
40 
41 
42 /*
43  * This routine needs to be supplied by whatever uses this file.
44  */
45 char *strchr(const char *s, int c);
46 
47 
48 #define	ISNTWORDCH(c)	((c) == '\0' || ISSPACE(c))
49 
50 
51 /*
52  * Prepare a gos_params structure for use by getoptstr().
53  */
54 void
55 getoptstr_init(struct gos_params *params)
56 {
57 	params->gos_pos = 1;
58 }
59 
60 /*
61  * Modeled after lib/libc/port/gen/getopt.c.
62  *
63  * With params->gos_opts set to a string of options and params->gos_strp set to
64  * an argument string, getoptstr returns
65  *   * the next option letter, where the options are given by the
66  *     params->gos_opts string.  If the option is followed by a ':' in gos_opts,
67  *     then params->gos_optargp will point to the beginning of the argument in
68  *     the string, and params->gos_optarglen will contain its length.
69  *   * -1 if "--" or a non-option argument is encountered.  In the former
70  *     case, params->gos_strp is advanced to the next argument.
71  *   * '?' if an illegal option is encountered or if an argument is not
72  *     supplied for an option which requires one and ':' is not the first
73  *     character of opts.  In both cases, the option letter is available in
74  *     params->gos_last_opt, and in the former case, params->gos_errp will
75  *     point to the offending character.
76  *   * ':' if an argument is not supplied for an option which requires one and
77  *     ':' is the first character of params->gos_opts.
78  */
79 int
80 getoptstr(struct gos_params *params)
81 {
82 	char c;
83 	char *cp;
84 
85 	/*
86 	 * const because we should update params.  Just make sure you don't
87 	 * use this after you update params->gos_strp.
88 	 */
89 	const char * const strp = params->gos_strp;
90 
91 
92 	if (params->gos_opts == NULL || strp == NULL)
93 		return (-1);
94 
95 	if (params->gos_pos == 1) {
96 		/* At beginning of new word. */
97 
98 		if (strp[0] == '\0' || strp[0] != '-')
99 			return (-1);
100 		if (ISNTWORDCH(strp[1])) {
101 			/* Lone dash. */
102 			return (-1);
103 		}
104 
105 		/* Check for "--" */
106 		if (strp[1] == '-' && ISNTWORDCH(strp[2])) {
107 			params->gos_strp = &strp[2];
108 			SKIP_SPC(params->gos_strp);
109 			return (-1);
110 		}
111 	}
112 
113 	params->gos_last_opt = c = strp[params->gos_pos];
114 	if (c == ':' || (cp = strchr(params->gos_opts, c)) == NULL) {
115 		/* Unrecognized option error. */
116 		params->gos_errp = &strp[params->gos_pos];
117 		++params->gos_pos;
118 		if (ISNTWORDCH(strp[params->gos_pos])) {
119 			params->gos_strp = &strp[params->gos_pos];
120 			SKIP_SPC(params->gos_strp);
121 			params->gos_pos = 1;
122 		}
123 		return ('?');
124 	}
125 
126 	if (cp[1] == ':') {
127 		/* This option expects an argument. */
128 
129 		params->gos_strp = &strp[params->gos_pos + 1];
130 
131 		if (ISNTWORDCH(*params->gos_strp)) {
132 			/* The argument is in the next word. */
133 			SKIP_SPC(params->gos_strp);
134 
135 			if (*params->gos_strp == '\0') {
136 				/* Not.  Missing argument. */
137 				params->gos_pos = 1;
138 				params->gos_optargp = NULL;
139 				return (params->gos_opts[0] == ':' ? ':' : '?');
140 			}
141 		}
142 
143 		params->gos_optargp = params->gos_strp;
144 
145 		/* Advance to the next word. */
146 		SKIP_WORD(params->gos_strp);
147 		params->gos_optarglen = params->gos_strp - params->gos_optargp;
148 		SKIP_SPC(params->gos_strp);
149 
150 		params->gos_pos = 1;
151 	} else {
152 		++params->gos_pos;
153 		if (ISNTWORDCH(strp[params->gos_pos])) {
154 			params->gos_strp = &strp[params->gos_pos];
155 			SKIP_SPC(params->gos_strp);
156 			params->gos_pos = 1;
157 		}
158 		params->gos_optargp = NULL;
159 	}
160 	return (c);
161 }
162