args.c revision 1.33 1 1.33 rillig /* $NetBSD: args.c,v 1.33 2021/09/26 19:37:11 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.33 rillig __RCSID("$NetBSD: args.c,v 1.33 2021/09/26 19:37:11 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.1 cgd #include <stdio.h>
60 1.1 cgd #include <stdlib.h>
61 1.1 cgd #include <string.h>
62 1.15 rillig
63 1.14 kamil #include "indent.h"
64 1.14 kamil
65 1.14 kamil #define INDENT_VERSION "2.0"
66 1.1 cgd
67 1.14 kamil static void scan_profile(FILE *);
68 1.32 rillig void add_typedefs_from_file(const char *);
69 1.14 kamil
70 1.32 rillig static const char *option_source = "?";
71 1.14 kamil
72 1.25 rillig #if __STDC_VERSION__ >= 201112L
73 1.25 rillig #define assert_type(expr, type) _Generic((expr), type : (expr))
74 1.25 rillig #else
75 1.25 rillig #define assert_type(expr, type) (expr)
76 1.25 rillig #endif
77 1.25 rillig #define bool_option(name, value, var) \
78 1.32 rillig {name, true, value, assert_type(&(var), bool *)}
79 1.31 rillig #define int_option(name, var) \
80 1.32 rillig {name, false, false, assert_type(&(var), int *)}
81 1.25 rillig
82 1.1 cgd /*
83 1.1 cgd * N.B.: because of the way the table here is scanned, options whose names are
84 1.29 rillig * a prefix of other options must occur later; that is, with -lp vs -l, -lp
85 1.29 rillig * must be first and -l must be last.
86 1.32 rillig *
87 1.32 rillig * See also set_special_option.
88 1.1 cgd */
89 1.29 rillig static const struct pro {
90 1.33 rillig const char p_name[6]; /* name, e.g. "bl", "cli" */
91 1.33 rillig bool p_is_bool;
92 1.33 rillig bool p_bool_value;
93 1.33 rillig void *p_obj; /* the associated variable (bool, int) */
94 1.33 rillig } pro[] = {
95 1.31 rillig bool_option("bacc", true, opt.blanklines_around_conditional_compilation),
96 1.31 rillig bool_option("badp", true, opt.blanklines_after_declarations_at_proctop),
97 1.31 rillig bool_option("bad", true, opt.blanklines_after_declarations),
98 1.31 rillig bool_option("bap", true, opt.blanklines_after_procs),
99 1.31 rillig bool_option("bbb", true, opt.blanklines_before_blockcomments),
100 1.31 rillig bool_option("bc", false, opt.leave_comma),
101 1.31 rillig bool_option("bl", false, opt.btype_2),
102 1.31 rillig bool_option("br", true, opt.btype_2),
103 1.31 rillig bool_option("bs", true, opt.blank_after_sizeof),
104 1.31 rillig bool_option("cdb", true, opt.comment_delimiter_on_blankline),
105 1.31 rillig int_option("cd", opt.decl_comment_column),
106 1.31 rillig bool_option("ce", true, opt.cuddle_else),
107 1.31 rillig int_option("ci", opt.continuation_indent),
108 1.31 rillig bool_option("cs", true, opt.space_after_cast),
109 1.31 rillig int_option("c", opt.comment_column),
110 1.31 rillig int_option("di", opt.decl_indent),
111 1.31 rillig bool_option("dj", true, opt.ljust_decl),
112 1.31 rillig int_option("d", opt.unindent_displace),
113 1.31 rillig bool_option("eei", true, opt.extra_expression_indent),
114 1.31 rillig bool_option("ei", true, opt.else_if),
115 1.31 rillig bool_option("fbs", true, opt.function_brace_split),
116 1.31 rillig bool_option("fc1", true, opt.format_col1_comments),
117 1.31 rillig bool_option("fcb", true, opt.format_block_comments),
118 1.31 rillig bool_option("ip", true, opt.indent_parameters),
119 1.31 rillig int_option("i", opt.indent_size),
120 1.31 rillig int_option("lc", opt.block_comment_max_line_length),
121 1.31 rillig int_option("ldi", opt.local_decl_indent),
122 1.31 rillig bool_option("lpl", true, opt.lineup_to_parens_always),
123 1.31 rillig bool_option("lp", true, opt.lineup_to_parens),
124 1.31 rillig int_option("l", opt.max_line_length),
125 1.31 rillig bool_option("nbacc", false, opt.blanklines_around_conditional_compilation),
126 1.31 rillig bool_option("nbadp", false, opt.blanklines_after_declarations_at_proctop),
127 1.31 rillig bool_option("nbad", false, opt.blanklines_after_declarations),
128 1.31 rillig bool_option("nbap", false, opt.blanklines_after_procs),
129 1.31 rillig bool_option("nbbb", false, opt.blanklines_before_blockcomments),
130 1.31 rillig bool_option("nbc", true, opt.leave_comma),
131 1.31 rillig bool_option("nbs", false, opt.blank_after_sizeof),
132 1.31 rillig bool_option("ncdb", false, opt.comment_delimiter_on_blankline),
133 1.31 rillig bool_option("nce", false, opt.cuddle_else),
134 1.31 rillig bool_option("ncs", false, opt.space_after_cast),
135 1.31 rillig bool_option("ndj", false, opt.ljust_decl),
136 1.31 rillig bool_option("neei", false, opt.extra_expression_indent),
137 1.31 rillig bool_option("nei", false, opt.else_if),
138 1.31 rillig bool_option("nfbs", false, opt.function_brace_split),
139 1.31 rillig bool_option("nfc1", false, opt.format_col1_comments),
140 1.31 rillig bool_option("nfcb", false, opt.format_block_comments),
141 1.31 rillig bool_option("nip", false, opt.indent_parameters),
142 1.31 rillig bool_option("nlpl", false, opt.lineup_to_parens_always),
143 1.31 rillig bool_option("nlp", false, opt.lineup_to_parens),
144 1.31 rillig bool_option("npcs", false, opt.proc_calls_space),
145 1.31 rillig bool_option("npsl", false, opt.procnames_start_line),
146 1.31 rillig bool_option("nsc", false, opt.star_comment_cont),
147 1.31 rillig bool_option("nsob", false, opt.swallow_optional_blanklines),
148 1.31 rillig bool_option("nut", false, opt.use_tabs),
149 1.31 rillig bool_option("nv", false, opt.verbose),
150 1.31 rillig bool_option("pcs", true, opt.proc_calls_space),
151 1.31 rillig bool_option("psl", true, opt.procnames_start_line),
152 1.31 rillig bool_option("sc", true, opt.star_comment_cont),
153 1.31 rillig bool_option("sob", true, opt.swallow_optional_blanklines),
154 1.31 rillig bool_option("ta", true, opt.auto_typedefs),
155 1.31 rillig int_option("ts", opt.tabsize),
156 1.31 rillig bool_option("ut", true, opt.use_tabs),
157 1.31 rillig bool_option("v", true, opt.verbose),
158 1.1 cgd };
159 1.14 kamil
160 1.1 cgd /*
161 1.1 cgd * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments
162 1.1 cgd * given in these files.
163 1.1 cgd */
164 1.5 lukem void
165 1.14 kamil set_profile(const char *profile_name)
166 1.1 cgd {
167 1.14 kamil FILE *f;
168 1.14 kamil char fname[PATH_MAX];
169 1.14 kamil static char prof[] = ".indent.pro";
170 1.5 lukem
171 1.14 kamil if (profile_name == NULL)
172 1.8 itojun snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), prof);
173 1.14 kamil else
174 1.14 kamil snprintf(fname, sizeof(fname), "%s", profile_name + 2);
175 1.14 kamil if ((f = fopen(option_source = fname, "r")) != NULL) {
176 1.14 kamil scan_profile(f);
177 1.33 rillig (void)fclose(f);
178 1.14 kamil }
179 1.14 kamil if ((f = fopen(option_source = prof, "r")) != NULL) {
180 1.14 kamil scan_profile(f);
181 1.33 rillig (void)fclose(f);
182 1.14 kamil }
183 1.14 kamil option_source = "Command line";
184 1.1 cgd }
185 1.1 cgd
186 1.14 kamil static void
187 1.7 wiz scan_profile(FILE *f)
188 1.1 cgd {
189 1.33 rillig int comment_index, i;
190 1.33 rillig char *p;
191 1.33 rillig char buf[BUFSIZ];
192 1.14 kamil
193 1.22 rillig for (;;) {
194 1.14 kamil p = buf;
195 1.15 rillig comment_index = 0;
196 1.14 kamil while ((i = getc(f)) != EOF) {
197 1.25 rillig if (i == '*' && comment_index == 0 && p > buf && p[-1] == '/') {
198 1.22 rillig comment_index = (int)(p - buf);
199 1.14 kamil *p++ = i;
200 1.25 rillig } else if (i == '/' && comment_index != 0 && p > buf && p[-1] == '*') {
201 1.15 rillig p = buf + comment_index - 1;
202 1.15 rillig comment_index = 0;
203 1.14 kamil } else if (isspace((unsigned char)i)) {
204 1.25 rillig if (p > buf && comment_index == 0)
205 1.14 kamil break;
206 1.14 kamil } else {
207 1.14 kamil *p++ = i;
208 1.14 kamil }
209 1.1 cgd }
210 1.14 kamil if (p != buf) {
211 1.14 kamil *p++ = 0;
212 1.14 kamil if (opt.verbose)
213 1.14 kamil printf("profile: %s\n", buf);
214 1.14 kamil set_option(buf);
215 1.19 rillig } else if (i == EOF)
216 1.14 kamil return;
217 1.14 kamil }
218 1.1 cgd }
219 1.1 cgd
220 1.14 kamil static const char *
221 1.30 rillig skip_over(const char *s, const char *prefix)
222 1.1 cgd {
223 1.30 rillig while (*prefix != '\0') {
224 1.30 rillig if (*prefix++ != *s++)
225 1.16 rillig return NULL;
226 1.14 kamil }
227 1.30 rillig return s;
228 1.1 cgd }
229 1.14 kamil
230 1.32 rillig static bool
231 1.32 rillig set_special_option(const char *arg)
232 1.32 rillig {
233 1.32 rillig const char *arg_end;
234 1.32 rillig
235 1.32 rillig if (strncmp(arg, "-version", 8) == 0) {
236 1.32 rillig printf("FreeBSD indent %s\n", INDENT_VERSION);
237 1.32 rillig exit(0);
238 1.33 rillig /* NOTREACHED */
239 1.32 rillig }
240 1.32 rillig
241 1.32 rillig if (arg[0] == 'P' || strncmp(arg, "npro", 4) == 0)
242 1.32 rillig return true;
243 1.32 rillig
244 1.32 rillig if (strncmp(arg, "cli", 3) == 0) {
245 1.32 rillig arg_end = arg + 3;
246 1.32 rillig if (arg_end[0] == '\0')
247 1.32 rillig goto need_param;
248 1.32 rillig opt.case_indent = atof(arg_end);
249 1.32 rillig return true;
250 1.32 rillig }
251 1.32 rillig
252 1.32 rillig if (strncmp(arg, "st", 2) == 0) {
253 1.32 rillig if (input == NULL)
254 1.32 rillig input = stdin;
255 1.32 rillig if (output == NULL)
256 1.32 rillig output = stdout;
257 1.32 rillig return true;
258 1.32 rillig }
259 1.32 rillig
260 1.32 rillig if (arg[0] == 'T') {
261 1.32 rillig arg_end = arg + 1;
262 1.32 rillig if (arg_end[0] == '\0')
263 1.32 rillig goto need_param;
264 1.32 rillig add_typename(arg_end);
265 1.32 rillig return true;
266 1.32 rillig }
267 1.32 rillig
268 1.32 rillig if (arg[0] == 'U') {
269 1.32 rillig arg_end = arg + 1;
270 1.32 rillig if (arg_end[0] == '\0')
271 1.32 rillig goto need_param;
272 1.32 rillig add_typedefs_from_file(arg_end);
273 1.32 rillig return true;
274 1.32 rillig }
275 1.32 rillig
276 1.32 rillig return false;
277 1.32 rillig
278 1.32 rillig need_param:
279 1.32 rillig errx(1, "%s: ``%.*s'' requires a parameter",
280 1.32 rillig option_source, (int)(arg_end - arg), arg);
281 1.32 rillig /* NOTREACHED */
282 1.32 rillig }
283 1.32 rillig
284 1.5 lukem void
285 1.29 rillig set_option(const char *arg)
286 1.1 cgd {
287 1.17 rillig const struct pro *p;
288 1.33 rillig const char *param_start;
289 1.1 cgd
290 1.14 kamil arg++; /* ignore leading "-" */
291 1.32 rillig if (set_special_option(arg))
292 1.32 rillig return;
293 1.32 rillig
294 1.32 rillig for (p = pro; p != pro + nitems(pro); p++)
295 1.30 rillig if (p->p_name[0] == arg[0])
296 1.30 rillig if ((param_start = skip_over(arg, p->p_name)) != NULL)
297 1.30 rillig goto found;
298 1.14 kamil errx(1, "%s: unknown parameter \"%s\"", option_source, arg - 1);
299 1.30 rillig
300 1.1 cgd found:
301 1.32 rillig if (p->p_is_bool)
302 1.32 rillig *(bool *)p->p_obj = p->p_bool_value;
303 1.32 rillig else {
304 1.32 rillig if (!isdigit((unsigned char)*param_start))
305 1.32 rillig errx(1, "%s: ``%s'' requires a parameter",
306 1.32 rillig option_source, p->p_name);
307 1.25 rillig *(int *)p->p_obj = atoi(param_start);
308 1.14 kamil }
309 1.14 kamil }
310 1.14 kamil
311 1.14 kamil void
312 1.30 rillig add_typedefs_from_file(const char *fname)
313 1.14 kamil {
314 1.14 kamil FILE *file;
315 1.14 kamil char line[BUFSIZ];
316 1.14 kamil
317 1.30 rillig if ((file = fopen(fname, "r")) == NULL) {
318 1.30 rillig fprintf(stderr, "indent: cannot open file %s\n", fname);
319 1.14 kamil exit(1);
320 1.14 kamil }
321 1.14 kamil while ((fgets(line, BUFSIZ, file)) != NULL) {
322 1.14 kamil /* Remove trailing whitespace */
323 1.14 kamil line[strcspn(line, " \t\n\r")] = '\0';
324 1.14 kamil add_typename(line);
325 1.14 kamil }
326 1.14 kamil fclose(file);
327 1.1 cgd }
328