GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* Copyright (C) 1984-2012 Mark Nudelman |
||
3 |
* Modified for use with illumos by Garrett D'Amore. |
||
4 |
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
||
5 |
* |
||
6 |
* You may distribute under the terms of either the GNU General Public |
||
7 |
* License or the Less License, as specified in the README file. |
||
8 |
* |
||
9 |
* For more information, see the README file. |
||
10 |
*/ |
||
11 |
|||
12 |
/* |
||
13 |
* Process command line options. |
||
14 |
* |
||
15 |
* Each option is a single letter which controls a program variable. |
||
16 |
* The options have defaults which may be changed via |
||
17 |
* the command line option, toggled via the "-" command, |
||
18 |
* or queried via the "_" command. |
||
19 |
*/ |
||
20 |
|||
21 |
#include "less.h" |
||
22 |
#include "option.h" |
||
23 |
|||
24 |
static struct loption *pendopt; |
||
25 |
int plusoption = FALSE; |
||
26 |
|||
27 |
static char *optstring(char *, char **, char *, char *); |
||
28 |
static int flip_triple(int, int); |
||
29 |
|||
30 |
extern int screen_trashed; |
||
31 |
extern int less_is_more; |
||
32 |
extern int quit_at_eof; |
||
33 |
extern char *every_first_cmd; |
||
34 |
extern int opt_use_backslash; |
||
35 |
|||
36 |
/* |
||
37 |
* Return a printable description of an option. |
||
38 |
*/ |
||
39 |
static char * |
||
40 |
opt_desc(struct loption *o) |
||
41 |
{ |
||
42 |
static char buf[OPTNAME_MAX + 10]; |
||
43 |
if (o->oletter == OLETTER_NONE) |
||
44 |
(void) snprintf(buf, sizeof (buf), "--%s", o->onames->oname); |
||
45 |
else |
||
46 |
(void) snprintf(buf, sizeof (buf), "-%c (--%s)", |
||
47 |
o->oletter, o->onames->oname); |
||
48 |
return (buf); |
||
49 |
} |
||
50 |
|||
51 |
/* |
||
52 |
* Return a string suitable for printing as the "name" of an option. |
||
53 |
* For example, if the option letter is 'x', just return "-x". |
||
54 |
*/ |
||
55 |
char * |
||
56 |
propt(int c) |
||
57 |
{ |
||
58 |
static char buf[8]; |
||
59 |
|||
60 |
20 |
(void) snprintf(buf, sizeof (buf), "-%s", prchar(c)); |
|
61 |
10 |
return (buf); |
|
62 |
} |
||
63 |
|||
64 |
/* |
||
65 |
* Scan an argument (either from the command line or from the |
||
66 |
* LESS environment variable) and process it. |
||
67 |
*/ |
||
68 |
void |
||
69 |
scan_option(char *s) |
||
70 |
{ |
||
71 |
struct loption *o; |
||
72 |
int optc; |
||
73 |
15 |
char *optname; |
|
74 |
char *printopt; |
||
75 |
15 |
char *str; |
|
76 |
int set_default; |
||
77 |
int lc; |
||
78 |
15 |
int err; |
|
79 |
int moreopt; |
||
80 |
15 |
PARG parg; |
|
81 |
|||
82 |
✗✓ | 15 |
if (s == NULL) |
83 |
return; |
||
84 |
|||
85 |
/* |
||
86 |
* If we have a pending option which requires an argument, |
||
87 |
* handle it now. |
||
88 |
* This happens if the previous option was, for example, "-P" |
||
89 |
* without a following string. In that case, the current |
||
90 |
* option is simply the argument for the previous option. |
||
91 |
*/ |
||
92 |
✓✓ | 15 |
if (pendopt != NULL) { |
93 |
✓✗✓ | 10 |
switch (pendopt->otype & OTYPE) { |
94 |
case STRING: |
||
95 |
5 |
(*pendopt->ofunc)(INIT, s); |
|
96 |
5 |
break; |
|
97 |
case NUMBER: |
||
98 |
printopt = opt_desc(pendopt); |
||
99 |
*(pendopt->ovar) = getnum(&s, printopt, NULL); |
||
100 |
break; |
||
101 |
} |
||
102 |
5 |
pendopt = NULL; |
|
103 |
5 |
return; |
|
104 |
} |
||
105 |
|||
106 |
set_default = FALSE; |
||
107 |
10 |
optname = NULL; |
|
108 |
moreopt = 0; |
||
109 |
o = NULL; |
||
110 |
|||
111 |
✓✓ | 40 |
while (*s != '\0') { |
112 |
/* |
||
113 |
* Check some special cases first. |
||
114 |
*/ |
||
115 |
✗✗✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓ |
30 |
switch (optc = *s++) { |
116 |
case ' ': |
||
117 |
case '\t': |
||
118 |
case END_OPTION_STRING: |
||
119 |
continue; |
||
120 |
case '-': |
||
121 |
/* |
||
122 |
* "--" indicates an option name instead of a letter. |
||
123 |
*/ |
||
124 |
✗✓ | 10 |
if (*s == '-') { |
125 |
if (!less_is_more) { |
||
126 |
optname = ++s; |
||
127 |
} |
||
128 |
break; |
||
129 |
} |
||
130 |
/* |
||
131 |
* "-+" means set these options back to their defaults. |
||
132 |
* (They may have been set otherwise by previous |
||
133 |
* options.) |
||
134 |
*/ |
||
135 |
✓✗ | 10 |
if (!less_is_more) { |
136 |
set_default = (*s == '+'); |
||
137 |
if (set_default) |
||
138 |
s++; |
||
139 |
} |
||
140 |
continue; |
||
141 |
case '+': |
||
142 |
/* |
||
143 |
* An option prefixed by a "+" is ungotten, so |
||
144 |
* that it is interpreted as less commands |
||
145 |
* processed at the start of the first input file. |
||
146 |
* "++" means process the commands at the start of |
||
147 |
* EVERY input file. |
||
148 |
*/ |
||
149 |
plusoption = TRUE; |
||
150 |
s = optstring(s, &str, propt('+'), NULL); |
||
151 |
if (s == NULL) |
||
152 |
return; |
||
153 |
if (*str == '+') |
||
154 |
every_first_cmd = estrdup(str+1); |
||
155 |
else |
||
156 |
ungetsc(str); |
||
157 |
free(str); |
||
158 |
continue; |
||
159 |
case '0': case '1': case '2': case '3': case '4': |
||
160 |
case '5': case '6': case '7': case '8': case '9': |
||
161 |
/* |
||
162 |
* Special "more" compatibility form "-<number>" |
||
163 |
* instead of -z<number> to set the scrolling |
||
164 |
* window size. |
||
165 |
*/ |
||
166 |
s--; |
||
167 |
optc = 'z'; |
||
168 |
moreopt = 1; |
||
169 |
break; |
||
170 |
case 'n': |
||
171 |
if (less_is_more) { |
||
172 |
moreopt = 1; |
||
173 |
optc = 'z'; |
||
174 |
} |
||
175 |
break; |
||
176 |
case 'i': |
||
177 |
if (less_is_more) { |
||
178 |
moreopt = 1; |
||
179 |
optc = 'I'; |
||
180 |
} |
||
181 |
break; |
||
182 |
case 'u': |
||
183 |
if (less_is_more) { |
||
184 |
moreopt = 1; |
||
185 |
optc = 'U'; |
||
186 |
} |
||
187 |
break; |
||
188 |
case 'e': |
||
189 |
if (less_is_more) { |
||
190 |
moreopt = 1; |
||
191 |
optc = 'E'; |
||
192 |
} |
||
193 |
break; |
||
194 |
case 'h': |
||
195 |
if (less_is_more) { |
||
196 |
moreopt = 1; |
||
197 |
optc = '?'; |
||
198 |
} |
||
199 |
break; |
||
200 |
case 'd': |
||
201 |
if (less_is_more) { |
||
202 |
moreopt = 1; |
||
203 |
optc = 'M'; |
||
204 |
} |
||
205 |
break; |
||
206 |
} |
||
207 |
|||
208 |
/* |
||
209 |
* Not a special case. |
||
210 |
* Look up the option letter in the option table. |
||
211 |
*/ |
||
212 |
10 |
err = 0; |
|
213 |
✓✗ | 10 |
if (optname == NULL) { |
214 |
10 |
printopt = propt(optc); |
|
215 |
10 |
lc = islower(optc); |
|
216 |
10 |
o = findopt(optc); |
|
217 |
✓✗✗✓ |
20 |
if (less_is_more && (!moreopt) && (o != NULL) && |
218 |
10 |
((o->otype & MORE_OK) == 0)) { |
|
219 |
o = NULL; |
||
220 |
} |
||
221 |
} else { |
||
222 |
printopt = optname; |
||
223 |
lc = islower(optname[0]); |
||
224 |
o = findopt_name(&optname, NULL, &err); |
||
225 |
s = optname; |
||
226 |
optname = NULL; |
||
227 |
switch (*s) { |
||
228 |
case ' ': /* name matches exactly */ |
||
229 |
case '\0': |
||
230 |
break; |
||
231 |
|||
232 |
case '=': /* name followed by "=value" */ |
||
233 |
if (o != NULL && |
||
234 |
(o->otype & OTYPE) != STRING && |
||
235 |
(o->otype & OTYPE) != NUMBER) { |
||
236 |
parg.p_string = printopt; |
||
237 |
error("The %s option should not be " |
||
238 |
"followed by =", &parg); |
||
239 |
return; |
||
240 |
} |
||
241 |
s++; |
||
242 |
break; |
||
243 |
default: /* name longer than option, bad */ |
||
244 |
o = NULL; |
||
245 |
} |
||
246 |
} |
||
247 |
✗✓ | 10 |
if (o == NULL) { |
248 |
parg.p_string = printopt; |
||
249 |
if (less_is_more) { |
||
250 |
error("Illegal option %s (more -h for help)", |
||
251 |
&parg); |
||
252 |
} else if (err == OPT_AMBIG) { |
||
253 |
error("%s is an ambiguous abbreviation " |
||
254 |
"(\"less --help\" for help)", &parg); |
||
255 |
} else { |
||
256 |
error("There is no %s option " |
||
257 |
"(\"less --help\" for help)", &parg); |
||
258 |
} |
||
259 |
return; |
||
260 |
} |
||
261 |
|||
262 |
15 |
str = NULL; |
|
263 |
✓✗✓✗ ✓ |
15 |
switch (o->otype & OTYPE) { |
264 |
case BOOL: |
||
265 |
✗✓ | 5 |
if (set_default) |
266 |
*(o->ovar) = o->odefault; |
||
267 |
else |
||
268 |
5 |
*(o->ovar) = ! o->odefault; |
|
269 |
5 |
break; |
|
270 |
case TRIPLE: |
||
271 |
if (set_default) |
||
272 |
*(o->ovar) = o->odefault; |
||
273 |
else |
||
274 |
*(o->ovar) = flip_triple(o->odefault, lc); |
||
275 |
break; |
||
276 |
case STRING: |
||
277 |
✓✗ | 5 |
if (*s == '\0') { |
278 |
/* |
||
279 |
* Set pendopt and return. |
||
280 |
* We will get the string next time |
||
281 |
* scan_option is called. |
||
282 |
*/ |
||
283 |
5 |
pendopt = o; |
|
284 |
5 |
return; |
|
285 |
} |
||
286 |
/* |
||
287 |
* Don't do anything here. |
||
288 |
* All processing of STRING options is done by |
||
289 |
* the handling function. |
||
290 |
*/ |
||
291 |
while (*s == ' ') |
||
292 |
s++; |
||
293 |
s = optstring(s, &str, printopt, o->odesc[1]); |
||
294 |
if (s == NULL) |
||
295 |
return; |
||
296 |
break; |
||
297 |
case NUMBER: |
||
298 |
if (*s == '\0') { |
||
299 |
pendopt = o; |
||
300 |
return; |
||
301 |
} |
||
302 |
*(o->ovar) = getnum(&s, printopt, NULL); |
||
303 |
break; |
||
304 |
} |
||
305 |
/* |
||
306 |
* If the option has a handling function, call it. |
||
307 |
*/ |
||
308 |
✗✓ | 5 |
if (o->ofunc != NULL) |
309 |
(*o->ofunc)(INIT, str); |
||
310 |
5 |
free(str); |
|
311 |
} |
||
312 |
20 |
} |
|
313 |
|||
314 |
/* |
||
315 |
* Toggle command line flags from within the program. |
||
316 |
* Used by the "-" and "_" commands. |
||
317 |
* how_toggle may be: |
||
318 |
* OPT_NO_TOGGLE just report the current setting, without changing it. |
||
319 |
* OPT_TOGGLE invert the current setting |
||
320 |
* OPT_UNSET set to the default value |
||
321 |
* OPT_SET set to the inverse of the default value |
||
322 |
*/ |
||
323 |
void |
||
324 |
toggle_option(struct loption *o, int lower, char *s, int how_toggle) |
||
325 |
{ |
||
326 |
int num; |
||
327 |
int no_prompt; |
||
328 |
1 |
int err; |
|
329 |
1 |
PARG parg; |
|
330 |
|||
331 |
1 |
no_prompt = (how_toggle & OPT_NO_PROMPT); |
|
332 |
1 |
how_toggle &= ~OPT_NO_PROMPT; |
|
333 |
|||
334 |
✗✓ | 1 |
if (o == NULL) { |
335 |
error("No such option", NULL); |
||
336 |
return; |
||
337 |
} |
||
338 |
|||
339 |
✓✗✗✓ |
2 |
if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) { |
340 |
parg.p_string = opt_desc(o); |
||
341 |
error("Cannot change the %s option", &parg); |
||
342 |
return; |
||
343 |
} |
||
344 |
|||
345 |
✗✓✗✗ |
1 |
if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) { |
346 |
parg.p_string = opt_desc(o); |
||
347 |
error("Cannot query the %s option", &parg); |
||
348 |
return; |
||
349 |
} |
||
350 |
|||
351 |
/* |
||
352 |
* Check for something which appears to be a do_toggle |
||
353 |
* (because the "-" command was used), but really is not. |
||
354 |
* This could be a string option with no string, or |
||
355 |
* a number option with no number. |
||
356 |
*/ |
||
357 |
✗✓✓ | 2 |
switch (o->otype & OTYPE) { |
358 |
case STRING: |
||
359 |
case NUMBER: |
||
360 |
✓✗✓✗ |
2 |
if (how_toggle == OPT_TOGGLE && *s == '\0') |
361 |
1 |
how_toggle = OPT_NO_TOGGLE; |
|
362 |
break; |
||
363 |
} |
||
364 |
|||
365 |
✗✓✗✗ |
1 |
if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) |
366 |
repaint_hilite(0); |
||
367 |
|||
368 |
/* |
||
369 |
* Now actually toggle (change) the variable. |
||
370 |
*/ |
||
371 |
✗✓ | 1 |
if (how_toggle != OPT_NO_TOGGLE) { |
372 |
switch (o->otype & OTYPE) { |
||
373 |
case BOOL: |
||
374 |
/* |
||
375 |
* Boolean. |
||
376 |
*/ |
||
377 |
switch (how_toggle) { |
||
378 |
case OPT_TOGGLE: |
||
379 |
*(o->ovar) = ! *(o->ovar); |
||
380 |
break; |
||
381 |
case OPT_UNSET: |
||
382 |
*(o->ovar) = o->odefault; |
||
383 |
break; |
||
384 |
case OPT_SET: |
||
385 |
*(o->ovar) = ! o->odefault; |
||
386 |
break; |
||
387 |
} |
||
388 |
break; |
||
389 |
case TRIPLE: |
||
390 |
/* |
||
391 |
* Triple: |
||
392 |
* If user gave the lower case letter, then switch |
||
393 |
* to 1 unless already 1, in which case make it 0. |
||
394 |
* If user gave the upper case letter, then switch |
||
395 |
* to 2 unless already 2, in which case make it 0. |
||
396 |
*/ |
||
397 |
switch (how_toggle) { |
||
398 |
case OPT_TOGGLE: |
||
399 |
*(o->ovar) = flip_triple(*(o->ovar), lower); |
||
400 |
break; |
||
401 |
case OPT_UNSET: |
||
402 |
*(o->ovar) = o->odefault; |
||
403 |
break; |
||
404 |
case OPT_SET: |
||
405 |
*(o->ovar) = flip_triple(o->odefault, lower); |
||
406 |
break; |
||
407 |
} |
||
408 |
break; |
||
409 |
case STRING: |
||
410 |
/* |
||
411 |
* String: don't do anything here. |
||
412 |
* The handling function will do everything. |
||
413 |
*/ |
||
414 |
switch (how_toggle) { |
||
415 |
case OPT_SET: |
||
416 |
case OPT_UNSET: |
||
417 |
error("Cannot use \"-+\" or \"--\" " |
||
418 |
"for a string option", NULL); |
||
419 |
return; |
||
420 |
} |
||
421 |
break; |
||
422 |
case NUMBER: |
||
423 |
/* |
||
424 |
* Number: set the variable to the given number. |
||
425 |
*/ |
||
426 |
switch (how_toggle) { |
||
427 |
case OPT_TOGGLE: |
||
428 |
num = getnum(&s, NULL, &err); |
||
429 |
if (!err) |
||
430 |
*(o->ovar) = num; |
||
431 |
break; |
||
432 |
case OPT_UNSET: |
||
433 |
*(o->ovar) = o->odefault; |
||
434 |
break; |
||
435 |
case OPT_SET: |
||
436 |
error("Can't use \"-!\" for a numeric option", |
||
437 |
NULL); |
||
438 |
return; |
||
439 |
} |
||
440 |
break; |
||
441 |
} |
||
442 |
} |
||
443 |
|||
444 |
/* |
||
445 |
* Call the handling function for any special action |
||
446 |
* specific to this option. |
||
447 |
*/ |
||
448 |
✓✗ | 1 |
if (o->ofunc != NULL) |
449 |
1 |
(*o->ofunc)((how_toggle == OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); |
|
450 |
|||
451 |
✗✓✗✗ |
1 |
if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) |
452 |
chg_hilite(); |
||
453 |
|||
454 |
✓✗ | 1 |
if (!no_prompt) { |
455 |
/* |
||
456 |
* Print a message describing the new setting. |
||
457 |
*/ |
||
458 |
✗✗✗✓ |
1 |
switch (o->otype & OTYPE) { |
459 |
case BOOL: |
||
460 |
case TRIPLE: |
||
461 |
/* |
||
462 |
* Print the odesc message. |
||
463 |
*/ |
||
464 |
error(o->odesc[*(o->ovar)], NULL); |
||
465 |
break; |
||
466 |
case NUMBER: |
||
467 |
/* |
||
468 |
* The message is in odesc[1] and has a %d for |
||
469 |
* the value of the variable. |
||
470 |
*/ |
||
471 |
parg.p_int = *(o->ovar); |
||
472 |
error(o->odesc[1], &parg); |
||
473 |
break; |
||
474 |
case STRING: |
||
475 |
/* |
||
476 |
* Message was already printed by the handling function. |
||
477 |
*/ |
||
478 |
break; |
||
479 |
} |
||
480 |
} |
||
481 |
|||
482 |
✗✓✗✗ |
1 |
if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) |
483 |
screen_trashed = TRUE; |
||
484 |
2 |
} |
|
485 |
|||
486 |
/* |
||
487 |
* "Toggle" a triple-valued option. |
||
488 |
*/ |
||
489 |
static int |
||
490 |
flip_triple(int val, int lc) |
||
491 |
{ |
||
492 |
if (lc) |
||
493 |
return ((val == OPT_ON) ? OPT_OFF : OPT_ON); |
||
494 |
else |
||
495 |
return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); |
||
496 |
} |
||
497 |
|||
498 |
/* |
||
499 |
* Determine if an option takes a parameter. |
||
500 |
*/ |
||
501 |
int |
||
502 |
opt_has_param(struct loption *o) |
||
503 |
{ |
||
504 |
✗✓ | 2 |
if (o == NULL) |
505 |
return (0); |
||
506 |
✗✓ | 1 |
if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) |
507 |
return (0); |
||
508 |
1 |
return (1); |
|
509 |
1 |
} |
|
510 |
|||
511 |
/* |
||
512 |
* Return the prompt to be used for a given option letter. |
||
513 |
* Only string and number valued options have prompts. |
||
514 |
*/ |
||
515 |
char * |
||
516 |
opt_prompt(struct loption *o) |
||
517 |
{ |
||
518 |
✓✗✗✓ |
3 |
if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) |
519 |
return ("?"); |
||
520 |
1 |
return (o->odesc[0]); |
|
521 |
1 |
} |
|
522 |
|||
523 |
/* |
||
524 |
* Return whether or not there is a string option pending; |
||
525 |
* that is, if the previous option was a string-valued option letter |
||
526 |
* (like -P) without a following string. |
||
527 |
* In that case, the current option is taken to be the string for |
||
528 |
* the previous option. |
||
529 |
*/ |
||
530 |
int |
||
531 |
isoptpending(void) |
||
532 |
{ |
||
533 |
142 |
return (pendopt != NULL); |
|
534 |
} |
||
535 |
|||
536 |
/* |
||
537 |
* Print error message about missing string. |
||
538 |
*/ |
||
539 |
static void |
||
540 |
nostring(char *printopt) |
||
541 |
{ |
||
542 |
PARG parg; |
||
543 |
parg.p_string = printopt; |
||
544 |
error("Value is required after %s", &parg); |
||
545 |
} |
||
546 |
|||
547 |
/* |
||
548 |
* Print error message if a STRING type option is not followed by a string. |
||
549 |
*/ |
||
550 |
void |
||
551 |
nopendopt(void) |
||
552 |
{ |
||
553 |
nostring(opt_desc(pendopt)); |
||
554 |
} |
||
555 |
|||
556 |
/* |
||
557 |
* Scan to end of string or to an END_OPTION_STRING character. |
||
558 |
* In the latter case, replace the char with a null char. |
||
559 |
* Return a pointer to the remainder of the string, if any. |
||
560 |
*/ |
||
561 |
static char * |
||
562 |
optstring(char *s, char **p_str, char *printopt, char *validchars) |
||
563 |
{ |
||
564 |
char *p; |
||
565 |
char *out; |
||
566 |
|||
567 |
if (*s == '\0') { |
||
568 |
nostring(printopt); |
||
569 |
return (NULL); |
||
570 |
} |
||
571 |
/* Alloc could be more than needed, but not worth trimming. */ |
||
572 |
*p_str = ecalloc(strlen(s)+1, sizeof (char)); |
||
573 |
out = *p_str; |
||
574 |
|||
575 |
for (p = s; *p != '\0'; p++) { |
||
576 |
if (opt_use_backslash && *p == '\\' && p[1] != '\0') { |
||
577 |
/* Take next char literally. */ |
||
578 |
++p; |
||
579 |
} else { |
||
580 |
if (*p == END_OPTION_STRING || |
||
581 |
(validchars != NULL && |
||
582 |
strchr(validchars, *p) == NULL)) |
||
583 |
/* End of option string. */ |
||
584 |
break; |
||
585 |
} |
||
586 |
*out++ = *p; |
||
587 |
} |
||
588 |
*out = '\0'; |
||
589 |
return (p); |
||
590 |
} |
||
591 |
|||
592 |
/* |
||
593 |
*/ |
||
594 |
static int |
||
595 |
num_error(char *printopt, int *errp) |
||
596 |
{ |
||
597 |
PARG parg; |
||
598 |
|||
599 |
if (errp != NULL) { |
||
600 |
*errp = TRUE; |
||
601 |
return (-1); |
||
602 |
} |
||
603 |
if (printopt != NULL) { |
||
604 |
parg.p_string = printopt; |
||
605 |
error("Number is required after %s", &parg); |
||
606 |
} |
||
607 |
return (-1); |
||
608 |
} |
||
609 |
|||
610 |
/* |
||
611 |
* Translate a string into a number. |
||
612 |
* Like atoi(), but takes a pointer to a char *, and updates |
||
613 |
* the char * to point after the translated number. |
||
614 |
*/ |
||
615 |
int |
||
616 |
getnum(char **sp, char *printopt, int *errp) |
||
617 |
{ |
||
618 |
char *s; |
||
619 |
int n; |
||
620 |
int neg; |
||
621 |
|||
622 |
s = skipsp(*sp); |
||
623 |
neg = FALSE; |
||
624 |
if (*s == '-') { |
||
625 |
neg = TRUE; |
||
626 |
s++; |
||
627 |
} |
||
628 |
if (*s < '0' || *s > '9') |
||
629 |
return (num_error(printopt, errp)); |
||
630 |
|||
631 |
n = 0; |
||
632 |
while (*s >= '0' && *s <= '9') |
||
633 |
n = 10 * n + *s++ - '0'; |
||
634 |
*sp = s; |
||
635 |
if (errp != NULL) |
||
636 |
*errp = FALSE; |
||
637 |
if (neg) |
||
638 |
n = -n; |
||
639 |
return (n); |
||
640 |
} |
||
641 |
|||
642 |
/* |
||
643 |
* Translate a string into a fraction, represented by the part of a |
||
644 |
* number which would follow a decimal point. |
||
645 |
* The value of the fraction is returned as parts per NUM_FRAC_DENOM. |
||
646 |
* That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM. |
||
647 |
*/ |
||
648 |
long |
||
649 |
getfraction(char **sp, char *printopt, int *errp) |
||
650 |
{ |
||
651 |
char *s; |
||
652 |
long frac = 0; |
||
653 |
int fraclen = 0; |
||
654 |
|||
655 |
s = skipsp(*sp); |
||
656 |
if (*s < '0' || *s > '9') |
||
657 |
return (num_error(printopt, errp)); |
||
658 |
|||
659 |
for (; *s >= '0' && *s <= '9'; s++) { |
||
660 |
frac = (frac * 10) + (*s - '0'); |
||
661 |
fraclen++; |
||
662 |
} |
||
663 |
if (fraclen > NUM_LOG_FRAC_DENOM) |
||
664 |
while (fraclen-- > NUM_LOG_FRAC_DENOM) |
||
665 |
frac /= 10; |
||
666 |
else |
||
667 |
while (fraclen++ < NUM_LOG_FRAC_DENOM) |
||
668 |
frac *= 10; |
||
669 |
*sp = s; |
||
670 |
if (errp != NULL) |
||
671 |
*errp = FALSE; |
||
672 |
return (frac); |
||
673 |
} |
||
674 |
|||
675 |
|||
676 |
/* |
||
677 |
* Get the value of the -e flag. |
||
678 |
*/ |
||
679 |
int |
||
680 |
get_quit_at_eof(void) |
||
681 |
{ |
||
682 |
3294 |
return (quit_at_eof); |
|
683 |
} |
Generated by: GCOVR (Version 3.3) |