args.c revision 1.29 1 1.29 rillig /* $NetBSD: args.c,v 1.29 2021/09/25 21:42:43 rillig Exp $ */
2 1.3 tls
3 1.14 kamil /*-
4 1.14 kamil * SPDX-License-Identifier: BSD-4-Clause
5 1.14 kamil *
6 1.14 kamil * Copyright (c) 1985 Sun Microsystems, Inc.
7 1.4 mrg * Copyright (c) 1980, 1993
8 1.4 mrg * The Regents of the University of California. All rights reserved.
9 1.1 cgd * All rights reserved.
10 1.1 cgd *
11 1.1 cgd * Redistribution and use in source and binary forms, with or without
12 1.1 cgd * modification, are permitted provided that the following conditions
13 1.1 cgd * are met:
14 1.1 cgd * 1. Redistributions of source code must retain the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer.
16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 cgd * notice, this list of conditions and the following disclaimer in the
18 1.1 cgd * documentation and/or other materials provided with the distribution.
19 1.1 cgd * 3. All advertising materials mentioning features or use of this software
20 1.1 cgd * must display the following acknowledgement:
21 1.1 cgd * This product includes software developed by the University of
22 1.1 cgd * California, Berkeley and its contributors.
23 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
24 1.1 cgd * may be used to endorse or promote products derived from this software
25 1.1 cgd * without specific prior written permission.
26 1.1 cgd *
27 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 1.1 cgd * SUCH DAMAGE.
38 1.1 cgd */
39 1.1 cgd
40 1.14 kamil #if 0
41 1.14 kamil static char sccsid[] = "@(#)args.c 8.1 (Berkeley) 6/6/93";
42 1.14 kamil #endif
43 1.14 kamil
44 1.5 lukem #include <sys/cdefs.h>
45 1.14 kamil #if defined(__NetBSD__)
46 1.29 rillig __RCSID("$NetBSD: args.c,v 1.29 2021/09/25 21:42:43 rillig Exp $");
47 1.14 kamil #elif defined(__FreeBSD__)
48 1.14 kamil __FBSDID("$FreeBSD: head/usr.bin/indent/args.c 336318 2018-07-15 21:04:21Z pstef $");
49 1.14 kamil #endif
50 1.1 cgd
51 1.1 cgd /*
52 1.1 cgd * Argument scanning and profile reading code. Default parameters are set
53 1.1 cgd * here as well.
54 1.1 cgd */
55 1.1 cgd
56 1.5 lukem #include <ctype.h>
57 1.12 ginsbach #include <err.h>
58 1.14 kamil #include <limits.h>
59 1.29 rillig #include <stdint.h>
60 1.1 cgd #include <stdio.h>
61 1.1 cgd #include <stdlib.h>
62 1.1 cgd #include <string.h>
63 1.15 rillig
64 1.14 kamil #include "indent.h"
65 1.14 kamil
66 1.14 kamil #define INDENT_VERSION "2.0"
67 1.1 cgd
68 1.1 cgd /* profile types */
69 1.1 cgd #define PRO_SPECIAL 1 /* special case */
70 1.1 cgd #define PRO_BOOL 2 /* boolean */
71 1.1 cgd #define PRO_INT 3 /* integer */
72 1.1 cgd
73 1.1 cgd /* profile specials for booleans */
74 1.1 cgd #define ON 1 /* turn it on */
75 1.1 cgd #define OFF 0 /* turn it off */
76 1.1 cgd
77 1.1 cgd /* profile specials for specials */
78 1.1 cgd #define IGN 1 /* ignore it */
79 1.1 cgd #define CLI 2 /* case label indent (float) */
80 1.1 cgd #define STDIN 3 /* use stdin */
81 1.1 cgd #define KEY 4 /* type (keyword) */
82 1.1 cgd
83 1.14 kamil static void scan_profile(FILE *);
84 1.14 kamil
85 1.18 rillig #define KEY_FILE 5 /* only used for args */
86 1.18 rillig #define VERSION 6 /* only used for args */
87 1.14 kamil
88 1.10 lukem const char *option_source = "?";
89 1.1 cgd
90 1.14 kamil void add_typedefs_from_file(const char *str);
91 1.14 kamil
92 1.25 rillig #if __STDC_VERSION__ >= 201112L
93 1.25 rillig #define assert_type(expr, type) _Generic((expr), type : (expr))
94 1.25 rillig #else
95 1.25 rillig #define assert_type(expr, type) (expr)
96 1.25 rillig #endif
97 1.25 rillig #define bool_option(name, value, var) \
98 1.26 rillig {name, PRO_BOOL, value, assert_type(&(var), bool *)}
99 1.25 rillig #define int_option(name, value, var) \
100 1.25 rillig {name, PRO_INT, value, assert_type(&(var), int *)}
101 1.25 rillig #define special_option(name, value) \
102 1.25 rillig {name, PRO_SPECIAL, assert_type(value, int), NULL}
103 1.25 rillig
104 1.1 cgd /*
105 1.1 cgd * N.B.: because of the way the table here is scanned, options whose names are
106 1.29 rillig * a prefix of other options must occur later; that is, with -lp vs -l, -lp
107 1.29 rillig * must be first and -l must be last.
108 1.1 cgd */
109 1.29 rillig static const struct pro {
110 1.28 rillig const char p_name[9]; /* name, e.g. "bl", "cli" */
111 1.29 rillig uint8_t p_type; /* type (int, bool, special) */
112 1.14 kamil int p_special; /* depends on type */
113 1.29 rillig void *p_obj; /* the associated variable (bool, int) */
114 1.14 kamil } pro[] = {
115 1.25 rillig special_option("T", KEY),
116 1.25 rillig special_option("U", KEY_FILE),
117 1.25 rillig special_option("-version", VERSION),
118 1.25 rillig special_option("P", IGN),
119 1.25 rillig bool_option("bacc", ON, opt.blanklines_around_conditional_compilation),
120 1.25 rillig bool_option("badp", ON, opt.blanklines_after_declarations_at_proctop),
121 1.25 rillig bool_option("bad", ON, opt.blanklines_after_declarations),
122 1.25 rillig bool_option("bap", ON, opt.blanklines_after_procs),
123 1.25 rillig bool_option("bbb", ON, opt.blanklines_before_blockcomments),
124 1.25 rillig bool_option("bc", OFF, opt.leave_comma),
125 1.25 rillig bool_option("bl", OFF, opt.btype_2),
126 1.25 rillig bool_option("br", ON, opt.btype_2),
127 1.27 rillig bool_option("bs", ON, opt.blank_after_sizeof),
128 1.25 rillig bool_option("cdb", ON, opt.comment_delimiter_on_blankline),
129 1.25 rillig int_option("cd", 0, opt.decl_comment_column),
130 1.25 rillig bool_option("ce", ON, opt.cuddle_else),
131 1.25 rillig int_option("ci", 0, opt.continuation_indent),
132 1.25 rillig special_option("cli", CLI),
133 1.25 rillig bool_option("cs", ON, opt.space_after_cast),
134 1.25 rillig int_option("c", 0, opt.comment_column),
135 1.25 rillig int_option("di", 0, opt.decl_indent),
136 1.25 rillig bool_option("dj", ON, opt.ljust_decl),
137 1.25 rillig int_option("d", 0, opt.unindent_displace),
138 1.25 rillig bool_option("eei", ON, opt.extra_expression_indent),
139 1.25 rillig bool_option("ei", ON, opt.else_if),
140 1.25 rillig bool_option("fbs", ON, opt.function_brace_split),
141 1.25 rillig bool_option("fc1", ON, opt.format_col1_comments),
142 1.25 rillig bool_option("fcb", ON, opt.format_block_comments),
143 1.25 rillig bool_option("ip", ON, opt.indent_parameters),
144 1.25 rillig int_option("i", 0, opt.indent_size),
145 1.25 rillig int_option("lc", 0, opt.block_comment_max_line_length),
146 1.25 rillig int_option("ldi", 0, opt.local_decl_indent),
147 1.25 rillig bool_option("lpl", ON, opt.lineup_to_parens_always),
148 1.25 rillig bool_option("lp", ON, opt.lineup_to_parens),
149 1.25 rillig int_option("l", 0, opt.max_line_length),
150 1.25 rillig bool_option("nbacc", OFF, opt.blanklines_around_conditional_compilation),
151 1.25 rillig bool_option("nbadp", OFF, opt.blanklines_after_declarations_at_proctop),
152 1.25 rillig bool_option("nbad", OFF, opt.blanklines_after_declarations),
153 1.25 rillig bool_option("nbap", OFF, opt.blanklines_after_procs),
154 1.25 rillig bool_option("nbbb", OFF, opt.blanklines_before_blockcomments),
155 1.25 rillig bool_option("nbc", ON, opt.leave_comma),
156 1.27 rillig bool_option("nbs", OFF, opt.blank_after_sizeof),
157 1.25 rillig bool_option("ncdb", OFF, opt.comment_delimiter_on_blankline),
158 1.25 rillig bool_option("nce", OFF, opt.cuddle_else),
159 1.25 rillig bool_option("ncs", OFF, opt.space_after_cast),
160 1.25 rillig bool_option("ndj", OFF, opt.ljust_decl),
161 1.25 rillig bool_option("neei", OFF, opt.extra_expression_indent),
162 1.25 rillig bool_option("nei", OFF, opt.else_if),
163 1.25 rillig bool_option("nfbs", OFF, opt.function_brace_split),
164 1.25 rillig bool_option("nfc1", OFF, opt.format_col1_comments),
165 1.25 rillig bool_option("nfcb", OFF, opt.format_block_comments),
166 1.25 rillig bool_option("nip", OFF, opt.indent_parameters),
167 1.25 rillig bool_option("nlpl", OFF, opt.lineup_to_parens_always),
168 1.25 rillig bool_option("nlp", OFF, opt.lineup_to_parens),
169 1.25 rillig bool_option("npcs", OFF, opt.proc_calls_space),
170 1.25 rillig special_option("npro", IGN),
171 1.25 rillig bool_option("npsl", OFF, opt.procnames_start_line),
172 1.25 rillig bool_option("nsc", OFF, opt.star_comment_cont),
173 1.25 rillig bool_option("nsob", OFF, opt.swallow_optional_blanklines),
174 1.25 rillig bool_option("nut", OFF, opt.use_tabs),
175 1.25 rillig bool_option("nv", OFF, opt.verbose),
176 1.25 rillig bool_option("pcs", ON, opt.proc_calls_space),
177 1.25 rillig bool_option("psl", ON, opt.procnames_start_line),
178 1.25 rillig bool_option("sc", ON, opt.star_comment_cont),
179 1.25 rillig bool_option("sob", ON, opt.swallow_optional_blanklines),
180 1.25 rillig special_option("st", STDIN),
181 1.25 rillig bool_option("ta", ON, opt.auto_typedefs),
182 1.25 rillig int_option("ts", 0, opt.tabsize),
183 1.25 rillig bool_option("ut", ON, opt.use_tabs),
184 1.25 rillig bool_option("v", ON, opt.verbose),
185 1.14 kamil /* whew! */
186 1.28 rillig {"", 0, 0, 0}
187 1.1 cgd };
188 1.14 kamil
189 1.1 cgd /*
190 1.1 cgd * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments
191 1.1 cgd * given in these files.
192 1.1 cgd */
193 1.5 lukem void
194 1.14 kamil set_profile(const char *profile_name)
195 1.1 cgd {
196 1.14 kamil FILE *f;
197 1.14 kamil char fname[PATH_MAX];
198 1.14 kamil static char prof[] = ".indent.pro";
199 1.5 lukem
200 1.14 kamil if (profile_name == NULL)
201 1.8 itojun snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), prof);
202 1.14 kamil else
203 1.14 kamil snprintf(fname, sizeof(fname), "%s", profile_name + 2);
204 1.14 kamil if ((f = fopen(option_source = fname, "r")) != NULL) {
205 1.14 kamil scan_profile(f);
206 1.14 kamil (void) fclose(f);
207 1.14 kamil }
208 1.14 kamil if ((f = fopen(option_source = prof, "r")) != NULL) {
209 1.14 kamil scan_profile(f);
210 1.14 kamil (void) fclose(f);
211 1.14 kamil }
212 1.14 kamil option_source = "Command line";
213 1.1 cgd }
214 1.1 cgd
215 1.14 kamil static void
216 1.7 wiz scan_profile(FILE *f)
217 1.1 cgd {
218 1.15 rillig int comment_index, i;
219 1.14 kamil char *p;
220 1.14 kamil char buf[BUFSIZ];
221 1.14 kamil
222 1.22 rillig for (;;) {
223 1.14 kamil p = buf;
224 1.15 rillig comment_index = 0;
225 1.14 kamil while ((i = getc(f)) != EOF) {
226 1.25 rillig if (i == '*' && comment_index == 0 && p > buf && p[-1] == '/') {
227 1.22 rillig comment_index = (int)(p - buf);
228 1.14 kamil *p++ = i;
229 1.25 rillig } else if (i == '/' && comment_index != 0 && p > buf && p[-1] == '*') {
230 1.15 rillig p = buf + comment_index - 1;
231 1.15 rillig comment_index = 0;
232 1.14 kamil } else if (isspace((unsigned char)i)) {
233 1.25 rillig if (p > buf && comment_index == 0)
234 1.14 kamil break;
235 1.14 kamil } else {
236 1.14 kamil *p++ = i;
237 1.14 kamil }
238 1.1 cgd }
239 1.14 kamil if (p != buf) {
240 1.14 kamil *p++ = 0;
241 1.14 kamil if (opt.verbose)
242 1.14 kamil printf("profile: %s\n", buf);
243 1.14 kamil set_option(buf);
244 1.19 rillig } else if (i == EOF)
245 1.14 kamil return;
246 1.14 kamil }
247 1.1 cgd }
248 1.1 cgd
249 1.14 kamil static const char *
250 1.10 lukem eqin(const char *s1, const char *s2)
251 1.1 cgd {
252 1.25 rillig while (*s1 != '\0') {
253 1.14 kamil if (*s1++ != *s2++)
254 1.16 rillig return NULL;
255 1.14 kamil }
256 1.16 rillig return s2;
257 1.1 cgd }
258 1.14 kamil
259 1.5 lukem void
260 1.29 rillig set_option(const char *arg)
261 1.1 cgd {
262 1.17 rillig const struct pro *p;
263 1.14 kamil const char *param_start;
264 1.1 cgd
265 1.14 kamil arg++; /* ignore leading "-" */
266 1.28 rillig for (p = pro; p->p_name[0] != '\0'; p++)
267 1.14 kamil if (*p->p_name == *arg && (param_start = eqin(p->p_name, arg)) != NULL)
268 1.14 kamil goto found;
269 1.14 kamil errx(1, "%s: unknown parameter \"%s\"", option_source, arg - 1);
270 1.1 cgd found:
271 1.14 kamil switch (p->p_type) {
272 1.1 cgd
273 1.14 kamil case PRO_SPECIAL:
274 1.14 kamil switch (p->p_special) {
275 1.1 cgd
276 1.14 kamil case IGN:
277 1.14 kamil break;
278 1.1 cgd
279 1.14 kamil case CLI:
280 1.14 kamil if (*param_start == 0)
281 1.14 kamil goto need_param;
282 1.14 kamil opt.case_indent = atof(param_start);
283 1.14 kamil break;
284 1.14 kamil
285 1.14 kamil case STDIN:
286 1.14 kamil if (input == NULL)
287 1.14 kamil input = stdin;
288 1.14 kamil if (output == NULL)
289 1.14 kamil output = stdout;
290 1.14 kamil break;
291 1.14 kamil
292 1.14 kamil case KEY:
293 1.14 kamil if (*param_start == 0)
294 1.14 kamil goto need_param;
295 1.14 kamil add_typename(param_start);
296 1.14 kamil break;
297 1.14 kamil
298 1.14 kamil case KEY_FILE:
299 1.14 kamil if (*param_start == 0)
300 1.14 kamil goto need_param;
301 1.14 kamil add_typedefs_from_file(param_start);
302 1.14 kamil break;
303 1.14 kamil
304 1.14 kamil case VERSION:
305 1.14 kamil printf("FreeBSD indent %s\n", INDENT_VERSION);
306 1.14 kamil exit(0);
307 1.22 rillig /*NOTREACHED*/
308 1.1 cgd
309 1.5 lukem default:
310 1.14 kamil errx(1, "set_option: internal error: p_special %d", p->p_special);
311 1.14 kamil }
312 1.14 kamil break;
313 1.14 kamil
314 1.14 kamil case PRO_BOOL:
315 1.29 rillig *(bool *)p->p_obj = p->p_special == ON;
316 1.14 kamil break;
317 1.14 kamil
318 1.14 kamil case PRO_INT:
319 1.14 kamil if (!isdigit((unsigned char)*param_start)) {
320 1.14 kamil need_param:
321 1.14 kamil errx(1, "%s: ``%s'' requires a parameter", option_source, p->p_name);
322 1.1 cgd }
323 1.25 rillig *(int *)p->p_obj = atoi(param_start);
324 1.14 kamil break;
325 1.14 kamil
326 1.14 kamil default:
327 1.14 kamil errx(1, "set_option: internal error: p_type %d", p->p_type);
328 1.14 kamil }
329 1.14 kamil }
330 1.14 kamil
331 1.14 kamil void
332 1.14 kamil add_typedefs_from_file(const char *str)
333 1.14 kamil {
334 1.14 kamil FILE *file;
335 1.14 kamil char line[BUFSIZ];
336 1.14 kamil
337 1.14 kamil if ((file = fopen(str, "r")) == NULL) {
338 1.14 kamil fprintf(stderr, "indent: cannot open file %s\n", str);
339 1.14 kamil exit(1);
340 1.14 kamil }
341 1.14 kamil while ((fgets(line, BUFSIZ, file)) != NULL) {
342 1.14 kamil /* Remove trailing whitespace */
343 1.14 kamil line[strcspn(line, " \t\n\r")] = '\0';
344 1.14 kamil add_typename(line);
345 1.14 kamil }
346 1.14 kamil fclose(file);
347 1.1 cgd }
348