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