optfunc.c revision 1.4 1 1.4 simonb /* $NetBSD: optfunc.c,v 1.4 2023/10/06 05:49:49 simonb Exp $ */
2 1.1 tron
3 1.1 tron /*
4 1.4 simonb * Copyright (C) 1984-2023 Mark Nudelman
5 1.1 tron *
6 1.1 tron * You may distribute under the terms of either the GNU General Public
7 1.1 tron * License or the Less License, as specified in the README file.
8 1.1 tron *
9 1.3 tron * For more information, see the README file.
10 1.1 tron */
11 1.1 tron
12 1.1 tron
13 1.1 tron /*
14 1.1 tron * Handling functions for command line options.
15 1.1 tron *
16 1.1 tron * Most options are handled by the generic code in option.c.
17 1.1 tron * But all string options, and a few non-string options, require
18 1.1 tron * special handling specific to the particular option.
19 1.1 tron * This special processing is done by the "handling functions" in this file.
20 1.1 tron *
21 1.1 tron * Each handling function is passed a "type" and, if it is a string
22 1.1 tron * option, the string which should be "assigned" to the option.
23 1.1 tron * The type may be one of:
24 1.4 simonb * INIT The option is being initialized from the command line.
25 1.4 simonb * TOGGLE The option is being changed from within the program.
26 1.4 simonb * QUERY The setting of the option is merely being queried.
27 1.1 tron */
28 1.1 tron
29 1.1 tron #include "less.h"
30 1.1 tron #include "option.h"
31 1.1 tron
32 1.1 tron extern int nbufs;
33 1.1 tron extern int bufspace;
34 1.1 tron extern int pr_type;
35 1.1 tron extern int plusoption;
36 1.1 tron extern int swindow;
37 1.1 tron extern int sc_width;
38 1.1 tron extern int sc_height;
39 1.1 tron extern int secure;
40 1.1 tron extern int dohelp;
41 1.4 simonb extern int is_tty;
42 1.1 tron extern char openquote;
43 1.1 tron extern char closequote;
44 1.1 tron extern char *prproto[];
45 1.1 tron extern char *eqproto;
46 1.1 tron extern char *hproto;
47 1.1 tron extern char *wproto;
48 1.4 simonb extern char *every_first_cmd;
49 1.1 tron extern IFILE curr_ifile;
50 1.1 tron extern char version[];
51 1.1 tron extern int jump_sline;
52 1.4 simonb extern long jump_sline_fraction;
53 1.1 tron extern int shift_count;
54 1.4 simonb extern long shift_count_fraction;
55 1.4 simonb extern char rscroll_char;
56 1.4 simonb extern int rscroll_attr;
57 1.4 simonb extern int mousecap;
58 1.4 simonb extern int wheel_lines;
59 1.1 tron extern int less_is_more;
60 1.4 simonb extern int linenum_width;
61 1.4 simonb extern int status_col_width;
62 1.4 simonb extern int use_color;
63 1.4 simonb extern int want_filesize;
64 1.4 simonb extern int header_lines;
65 1.4 simonb extern int header_cols;
66 1.4 simonb extern int def_search_type;
67 1.4 simonb extern int chopline;
68 1.4 simonb extern int tabstops[];
69 1.4 simonb extern int ntabstops;
70 1.4 simonb extern int tabdefault;
71 1.4 simonb extern char intr_char;
72 1.1 tron #if LOGFILE
73 1.1 tron extern char *namelogfile;
74 1.1 tron extern int force_logfile;
75 1.1 tron extern int logfile;
76 1.1 tron #endif
77 1.1 tron #if TAGS
78 1.1 tron public char *tagoption = NULL;
79 1.1 tron extern char *tags;
80 1.4 simonb extern char ztags[];
81 1.1 tron #endif
82 1.4 simonb #if LESSTEST
83 1.4 simonb extern char *ttyin_name;
84 1.4 simonb #endif /*LESSTEST*/
85 1.1 tron #if MSDOS_COMPILER
86 1.1 tron extern int nm_fg_color, nm_bg_color;
87 1.1 tron extern int bo_fg_color, bo_bg_color;
88 1.1 tron extern int ul_fg_color, ul_bg_color;
89 1.1 tron extern int so_fg_color, so_bg_color;
90 1.1 tron extern int bl_fg_color, bl_bg_color;
91 1.4 simonb extern int sgr_mode;
92 1.4 simonb #if MSDOS_COMPILER==WIN32C
93 1.4 simonb #ifndef COMMON_LVB_UNDERSCORE
94 1.4 simonb #define COMMON_LVB_UNDERSCORE 0x8000
95 1.4 simonb #endif
96 1.4 simonb #endif
97 1.1 tron #endif
98 1.1 tron
99 1.1 tron
100 1.1 tron #if LOGFILE
101 1.1 tron /*
102 1.1 tron * Handler for -o option.
103 1.1 tron */
104 1.4 simonb public void opt_o(int type, char *s)
105 1.1 tron {
106 1.1 tron PARG parg;
107 1.4 simonb char *filename;
108 1.1 tron
109 1.1 tron if (secure)
110 1.1 tron {
111 1.1 tron error("log file support is not available", NULL_PARG);
112 1.1 tron return;
113 1.1 tron }
114 1.1 tron switch (type)
115 1.1 tron {
116 1.1 tron case INIT:
117 1.4 simonb namelogfile = save(s);
118 1.1 tron break;
119 1.1 tron case TOGGLE:
120 1.1 tron if (ch_getflags() & CH_CANSEEK)
121 1.1 tron {
122 1.1 tron error("Input is not a pipe", NULL_PARG);
123 1.1 tron return;
124 1.1 tron }
125 1.1 tron if (logfile >= 0)
126 1.1 tron {
127 1.1 tron error("Log file is already in use", NULL_PARG);
128 1.1 tron return;
129 1.1 tron }
130 1.1 tron s = skipsp(s);
131 1.4 simonb if (namelogfile != NULL)
132 1.4 simonb free(namelogfile);
133 1.4 simonb filename = lglob(s);
134 1.4 simonb namelogfile = shell_unquote(filename);
135 1.4 simonb free(filename);
136 1.1 tron use_logfile(namelogfile);
137 1.1 tron sync_logfile();
138 1.1 tron break;
139 1.1 tron case QUERY:
140 1.1 tron if (logfile < 0)
141 1.1 tron error("No log file", NULL_PARG);
142 1.1 tron else
143 1.1 tron {
144 1.1 tron parg.p_string = namelogfile;
145 1.1 tron error("Log file \"%s\"", &parg);
146 1.1 tron }
147 1.1 tron break;
148 1.1 tron }
149 1.1 tron }
150 1.1 tron
151 1.1 tron /*
152 1.1 tron * Handler for -O option.
153 1.1 tron */
154 1.4 simonb public void opt__O(int type, char *s)
155 1.1 tron {
156 1.1 tron force_logfile = TRUE;
157 1.1 tron opt_o(type, s);
158 1.1 tron }
159 1.1 tron #endif
160 1.1 tron
161 1.1 tron /*
162 1.1 tron * Handlers for -j option.
163 1.1 tron */
164 1.4 simonb public void opt_j(int type, char *s)
165 1.1 tron {
166 1.1 tron PARG parg;
167 1.1 tron int len;
168 1.1 tron int err;
169 1.1 tron
170 1.1 tron switch (type)
171 1.1 tron {
172 1.1 tron case INIT:
173 1.1 tron case TOGGLE:
174 1.1 tron if (*s == '.')
175 1.1 tron {
176 1.1 tron s++;
177 1.1 tron jump_sline_fraction = getfraction(&s, "j", &err);
178 1.1 tron if (err)
179 1.1 tron error("Invalid line fraction", NULL_PARG);
180 1.1 tron else
181 1.1 tron calc_jump_sline();
182 1.1 tron } else
183 1.1 tron {
184 1.1 tron int sline = getnum(&s, "j", &err);
185 1.1 tron if (err)
186 1.1 tron error("Invalid line number", NULL_PARG);
187 1.1 tron else
188 1.1 tron {
189 1.1 tron jump_sline = sline;
190 1.1 tron jump_sline_fraction = -1;
191 1.1 tron }
192 1.1 tron }
193 1.1 tron break;
194 1.1 tron case QUERY:
195 1.1 tron if (jump_sline_fraction < 0)
196 1.1 tron {
197 1.1 tron parg.p_int = jump_sline;
198 1.1 tron error("Position target at screen line %d", &parg);
199 1.1 tron } else
200 1.1 tron {
201 1.4 simonb char buf[INT_STRLEN_BOUND(long)+2];
202 1.4 simonb SNPRINTF1(buf, sizeof(buf), ".%06ld", jump_sline_fraction);
203 1.4 simonb len = (int) strlen(buf);
204 1.1 tron while (len > 2 && buf[len-1] == '0')
205 1.1 tron len--;
206 1.1 tron buf[len] = '\0';
207 1.1 tron parg.p_string = buf;
208 1.1 tron error("Position target at screen position %s", &parg);
209 1.1 tron }
210 1.1 tron break;
211 1.1 tron }
212 1.1 tron }
213 1.1 tron
214 1.4 simonb public void calc_jump_sline(void)
215 1.1 tron {
216 1.1 tron if (jump_sline_fraction < 0)
217 1.1 tron return;
218 1.4 simonb jump_sline = (int) muldiv(sc_height, jump_sline_fraction, NUM_FRAC_DENOM);
219 1.1 tron }
220 1.1 tron
221 1.1 tron /*
222 1.1 tron * Handlers for -# option.
223 1.1 tron */
224 1.4 simonb public void opt_shift(int type, char *s)
225 1.1 tron {
226 1.1 tron PARG parg;
227 1.1 tron int len;
228 1.1 tron int err;
229 1.1 tron
230 1.1 tron switch (type)
231 1.1 tron {
232 1.1 tron case INIT:
233 1.1 tron case TOGGLE:
234 1.1 tron if (*s == '.')
235 1.1 tron {
236 1.1 tron s++;
237 1.1 tron shift_count_fraction = getfraction(&s, "#", &err);
238 1.1 tron if (err)
239 1.1 tron error("Invalid column fraction", NULL_PARG);
240 1.1 tron else
241 1.1 tron calc_shift_count();
242 1.1 tron } else
243 1.1 tron {
244 1.1 tron int hs = getnum(&s, "#", &err);
245 1.1 tron if (err)
246 1.1 tron error("Invalid column number", NULL_PARG);
247 1.1 tron else
248 1.1 tron {
249 1.1 tron shift_count = hs;
250 1.1 tron shift_count_fraction = -1;
251 1.1 tron }
252 1.1 tron }
253 1.1 tron break;
254 1.1 tron case QUERY:
255 1.1 tron if (shift_count_fraction < 0)
256 1.1 tron {
257 1.1 tron parg.p_int = shift_count;
258 1.1 tron error("Horizontal shift %d columns", &parg);
259 1.1 tron } else
260 1.1 tron {
261 1.4 simonb char buf[INT_STRLEN_BOUND(long)+2];
262 1.4 simonb SNPRINTF1(buf, sizeof(buf), ".%06ld", shift_count_fraction);
263 1.4 simonb len = (int) strlen(buf);
264 1.1 tron while (len > 2 && buf[len-1] == '0')
265 1.1 tron len--;
266 1.1 tron buf[len] = '\0';
267 1.1 tron parg.p_string = buf;
268 1.1 tron error("Horizontal shift %s of screen width", &parg);
269 1.1 tron }
270 1.1 tron break;
271 1.1 tron }
272 1.1 tron }
273 1.4 simonb
274 1.4 simonb public void calc_shift_count(void)
275 1.1 tron {
276 1.1 tron if (shift_count_fraction < 0)
277 1.1 tron return;
278 1.4 simonb shift_count = (int) muldiv(sc_width, shift_count_fraction, NUM_FRAC_DENOM);
279 1.1 tron }
280 1.1 tron
281 1.1 tron #if USERFILE
282 1.4 simonb public void opt_k(int type, char *s)
283 1.1 tron {
284 1.1 tron PARG parg;
285 1.1 tron
286 1.1 tron switch (type)
287 1.1 tron {
288 1.1 tron case INIT:
289 1.1 tron if (lesskey(s, 0))
290 1.1 tron {
291 1.1 tron parg.p_string = s;
292 1.1 tron error("Cannot use lesskey file \"%s\"", &parg);
293 1.1 tron }
294 1.1 tron break;
295 1.1 tron }
296 1.1 tron }
297 1.4 simonb
298 1.4 simonb #if HAVE_LESSKEYSRC
299 1.4 simonb public void opt_ks(int type, char *s)
300 1.4 simonb {
301 1.4 simonb PARG parg;
302 1.4 simonb
303 1.4 simonb switch (type)
304 1.4 simonb {
305 1.4 simonb case INIT:
306 1.4 simonb if (lesskey_src(s, 0))
307 1.4 simonb {
308 1.4 simonb parg.p_string = s;
309 1.4 simonb error("Cannot use lesskey source file \"%s\"", &parg);
310 1.4 simonb }
311 1.4 simonb break;
312 1.4 simonb }
313 1.4 simonb }
314 1.4 simonb #endif /* HAVE_LESSKEYSRC */
315 1.4 simonb #endif /* USERFILE */
316 1.1 tron
317 1.1 tron #if TAGS
318 1.1 tron /*
319 1.1 tron * Handler for -t option.
320 1.1 tron */
321 1.4 simonb public void opt_t(int type, char *s)
322 1.1 tron {
323 1.1 tron IFILE save_ifile;
324 1.1 tron POSITION pos;
325 1.1 tron
326 1.1 tron switch (type)
327 1.1 tron {
328 1.1 tron case INIT:
329 1.4 simonb tagoption = save(s);
330 1.1 tron /* Do the rest in main() */
331 1.1 tron break;
332 1.1 tron case TOGGLE:
333 1.1 tron if (secure)
334 1.1 tron {
335 1.1 tron error("tags support is not available", NULL_PARG);
336 1.1 tron break;
337 1.1 tron }
338 1.1 tron findtag(skipsp(s));
339 1.1 tron save_ifile = save_curr_ifile();
340 1.1 tron /*
341 1.1 tron * Try to open the file containing the tag
342 1.1 tron * and search for the tag in that file.
343 1.1 tron */
344 1.1 tron if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
345 1.1 tron {
346 1.1 tron /* Failed: reopen the old file. */
347 1.1 tron reedit_ifile(save_ifile);
348 1.1 tron break;
349 1.1 tron }
350 1.1 tron unsave_ifile(save_ifile);
351 1.1 tron jump_loc(pos, jump_sline);
352 1.1 tron break;
353 1.1 tron }
354 1.1 tron }
355 1.1 tron
356 1.1 tron /*
357 1.1 tron * Handler for -T option.
358 1.1 tron */
359 1.4 simonb public void opt__T(int type, char *s)
360 1.1 tron {
361 1.1 tron PARG parg;
362 1.4 simonb char *filename;
363 1.1 tron
364 1.1 tron switch (type)
365 1.1 tron {
366 1.1 tron case INIT:
367 1.4 simonb tags = save(s);
368 1.1 tron break;
369 1.1 tron case TOGGLE:
370 1.1 tron s = skipsp(s);
371 1.4 simonb if (tags != NULL && tags != ztags)
372 1.4 simonb free(tags);
373 1.4 simonb filename = lglob(s);
374 1.4 simonb tags = shell_unquote(filename);
375 1.4 simonb free(filename);
376 1.1 tron break;
377 1.1 tron case QUERY:
378 1.1 tron parg.p_string = tags;
379 1.1 tron error("Tags file \"%s\"", &parg);
380 1.1 tron break;
381 1.1 tron }
382 1.1 tron }
383 1.1 tron #endif
384 1.1 tron
385 1.1 tron /*
386 1.1 tron * Handler for -p option.
387 1.1 tron */
388 1.4 simonb public void opt_p(int type, char *s)
389 1.1 tron {
390 1.1 tron switch (type)
391 1.1 tron {
392 1.1 tron case INIT:
393 1.1 tron /*
394 1.4 simonb * Unget a command for the specified string.
395 1.1 tron */
396 1.4 simonb if (less_is_more)
397 1.4 simonb {
398 1.4 simonb /*
399 1.4 simonb * In "more" mode, the -p argument is a command,
400 1.4 simonb * not a search string, so we don't need a slash.
401 1.4 simonb */
402 1.4 simonb every_first_cmd = save(s);
403 1.4 simonb } else
404 1.4 simonb {
405 1.4 simonb plusoption = TRUE;
406 1.4 simonb /*
407 1.4 simonb * {{ This won't work if the "/" command is
408 1.4 simonb * changed or invalidated by a .lesskey file. }}
409 1.4 simonb */
410 1.1 tron ungetsc("/");
411 1.4 simonb ungetsc(s);
412 1.4 simonb ungetcc_back(CHAR_END_COMMAND);
413 1.4 simonb }
414 1.1 tron break;
415 1.1 tron }
416 1.1 tron }
417 1.1 tron
418 1.1 tron /*
419 1.1 tron * Handler for -P option.
420 1.1 tron */
421 1.4 simonb public void opt__P(int type, char *s)
422 1.1 tron {
423 1.4 simonb char **proto;
424 1.1 tron PARG parg;
425 1.1 tron
426 1.1 tron switch (type)
427 1.1 tron {
428 1.1 tron case INIT:
429 1.1 tron case TOGGLE:
430 1.1 tron /*
431 1.1 tron * Figure out which prototype string should be changed.
432 1.1 tron */
433 1.1 tron switch (*s)
434 1.1 tron {
435 1.4 simonb case 's': proto = &prproto[PR_SHORT]; s++; break;
436 1.4 simonb case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
437 1.4 simonb case 'M': proto = &prproto[PR_LONG]; s++; break;
438 1.4 simonb case '=': proto = &eqproto; s++; break;
439 1.4 simonb case 'h': proto = &hproto; s++; break;
440 1.4 simonb case 'w': proto = &wproto; s++; break;
441 1.4 simonb default: proto = &prproto[PR_SHORT]; break;
442 1.1 tron }
443 1.1 tron free(*proto);
444 1.1 tron *proto = save(s);
445 1.1 tron break;
446 1.1 tron case QUERY:
447 1.1 tron parg.p_string = prproto[pr_type];
448 1.1 tron error("%s", &parg);
449 1.1 tron break;
450 1.1 tron }
451 1.1 tron }
452 1.1 tron
453 1.1 tron /*
454 1.1 tron * Handler for the -b option.
455 1.1 tron */
456 1.1 tron /*ARGSUSED*/
457 1.4 simonb public void opt_b(int type, char *s)
458 1.1 tron {
459 1.1 tron switch (type)
460 1.1 tron {
461 1.1 tron case INIT:
462 1.1 tron case TOGGLE:
463 1.1 tron /*
464 1.1 tron * Set the new number of buffers.
465 1.1 tron */
466 1.1 tron ch_setbufspace(bufspace);
467 1.1 tron break;
468 1.1 tron case QUERY:
469 1.1 tron break;
470 1.1 tron }
471 1.1 tron }
472 1.1 tron
473 1.1 tron /*
474 1.1 tron * Handler for the -i option.
475 1.1 tron */
476 1.1 tron /*ARGSUSED*/
477 1.4 simonb public void opt_i(int type, char *s)
478 1.1 tron {
479 1.1 tron switch (type)
480 1.1 tron {
481 1.1 tron case TOGGLE:
482 1.1 tron chg_caseless();
483 1.1 tron break;
484 1.1 tron case QUERY:
485 1.1 tron case INIT:
486 1.1 tron break;
487 1.1 tron }
488 1.1 tron }
489 1.1 tron
490 1.1 tron /*
491 1.1 tron * Handler for the -V option.
492 1.1 tron */
493 1.1 tron /*ARGSUSED*/
494 1.4 simonb public void opt__V(int type, char *s)
495 1.1 tron {
496 1.1 tron switch (type)
497 1.1 tron {
498 1.1 tron case TOGGLE:
499 1.1 tron case QUERY:
500 1.1 tron dispversion();
501 1.1 tron break;
502 1.1 tron case INIT:
503 1.4 simonb set_output(1); /* Force output to stdout per GNU standard for --version output. */
504 1.1 tron putstr("less ");
505 1.1 tron putstr(version);
506 1.3 tron putstr(" (");
507 1.4 simonb putstr(pattern_lib_name());
508 1.4 simonb putstr(" regular expressions)\n");
509 1.4 simonb {
510 1.4 simonb char constant *copyright =
511 1.4 simonb "Copyright (C) 1984-2023 Mark Nudelman\n\n";
512 1.4 simonb putstr(copyright);
513 1.4 simonb }
514 1.4 simonb if (version[strlen(version)-1] == 'x')
515 1.4 simonb {
516 1.4 simonb putstr("** This is an EXPERIMENTAL build of the 'less' software,\n");
517 1.4 simonb putstr("** and may not function correctly.\n");
518 1.4 simonb putstr("** Obtain release builds from the web page below.\n\n");
519 1.4 simonb }
520 1.4 simonb #if LESSTEST
521 1.4 simonb putstr("This build supports LESSTEST.\n");
522 1.4 simonb #endif /*LESSTEST*/
523 1.1 tron putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
524 1.1 tron putstr("For information about the terms of redistribution,\n");
525 1.1 tron putstr("see the file named README in the less distribution.\n");
526 1.4 simonb putstr("Home page: https://greenwoodsoftware.com/less\n");
527 1.1 tron quit(QUIT_OK);
528 1.1 tron break;
529 1.1 tron }
530 1.1 tron }
531 1.1 tron
532 1.1 tron #if MSDOS_COMPILER
533 1.1 tron /*
534 1.1 tron * Parse an MSDOS color descriptor.
535 1.1 tron */
536 1.4 simonb static void colordesc(char *s, int *fg_color, int *bg_color)
537 1.1 tron {
538 1.1 tron int fg, bg;
539 1.4 simonb #if MSDOS_COMPILER==WIN32C
540 1.4 simonb int ul = 0;
541 1.4 simonb
542 1.4 simonb if (*s == 'u')
543 1.1 tron {
544 1.4 simonb ul = COMMON_LVB_UNDERSCORE;
545 1.1 tron s++;
546 1.4 simonb if (*s == '\0')
547 1.1 tron {
548 1.4 simonb *fg_color = nm_fg_color | ul;
549 1.4 simonb *bg_color = nm_bg_color;
550 1.1 tron return;
551 1.1 tron }
552 1.1 tron }
553 1.4 simonb #endif
554 1.4 simonb if (parse_color(s, &fg, &bg) == CT_NULL)
555 1.4 simonb {
556 1.4 simonb PARG p;
557 1.4 simonb p.p_string = s;
558 1.4 simonb error("Invalid color string \"%s\"", &p);
559 1.4 simonb } else
560 1.4 simonb {
561 1.4 simonb if (fg == CV_NOCHANGE)
562 1.4 simonb fg = nm_fg_color;
563 1.4 simonb if (bg == CV_NOCHANGE)
564 1.4 simonb bg = nm_bg_color;
565 1.4 simonb #if MSDOS_COMPILER==WIN32C
566 1.4 simonb fg |= ul;
567 1.4 simonb #endif
568 1.4 simonb *fg_color = fg;
569 1.4 simonb *bg_color = bg;
570 1.4 simonb }
571 1.4 simonb }
572 1.4 simonb #endif
573 1.4 simonb
574 1.4 simonb static int color_from_namechar(char namechar)
575 1.4 simonb {
576 1.4 simonb switch (namechar)
577 1.4 simonb {
578 1.4 simonb case 'B': return AT_COLOR_BIN;
579 1.4 simonb case 'C': return AT_COLOR_CTRL;
580 1.4 simonb case 'E': return AT_COLOR_ERROR;
581 1.4 simonb case 'H': return AT_COLOR_HEADER;
582 1.4 simonb case 'M': return AT_COLOR_MARK;
583 1.4 simonb case 'N': return AT_COLOR_LINENUM;
584 1.4 simonb case 'P': return AT_COLOR_PROMPT;
585 1.4 simonb case 'R': return AT_COLOR_RSCROLL;
586 1.4 simonb case 'S': return AT_COLOR_SEARCH;
587 1.4 simonb case 'W': case 'A': return AT_COLOR_ATTN;
588 1.4 simonb case 'n': return AT_NORMAL;
589 1.4 simonb case 's': return AT_STANDOUT;
590 1.4 simonb case 'd': return AT_BOLD;
591 1.4 simonb case 'u': return AT_UNDERLINE;
592 1.4 simonb case 'k': return AT_BLINK;
593 1.4 simonb default:
594 1.4 simonb if (namechar >= '1' && namechar <= '0'+NUM_SEARCH_COLORS)
595 1.4 simonb return AT_COLOR_SUBSEARCH(namechar-'0');
596 1.4 simonb return -1;
597 1.4 simonb }
598 1.1 tron }
599 1.1 tron
600 1.1 tron /*
601 1.1 tron * Handler for the -D option.
602 1.1 tron */
603 1.1 tron /*ARGSUSED*/
604 1.4 simonb public void opt_D(int type, char *s)
605 1.1 tron {
606 1.4 simonb PARG p;
607 1.4 simonb int attr;
608 1.4 simonb
609 1.1 tron switch (type)
610 1.1 tron {
611 1.1 tron case INIT:
612 1.1 tron case TOGGLE:
613 1.4 simonb #if MSDOS_COMPILER
614 1.4 simonb if (*s == 'a')
615 1.1 tron {
616 1.4 simonb sgr_mode = !sgr_mode;
617 1.1 tron break;
618 1.1 tron }
619 1.4 simonb #endif
620 1.4 simonb attr = color_from_namechar(s[0]);
621 1.4 simonb if (attr < 0)
622 1.4 simonb {
623 1.4 simonb p.p_char = s[0];
624 1.4 simonb error("Invalid color specifier '%c'", &p);
625 1.4 simonb return;
626 1.4 simonb }
627 1.4 simonb if (!use_color && (attr & AT_COLOR))
628 1.4 simonb {
629 1.4 simonb error("Set --use-color before changing colors", NULL_PARG);
630 1.4 simonb return;
631 1.4 simonb }
632 1.4 simonb s++;
633 1.4 simonb #if MSDOS_COMPILER
634 1.4 simonb if (!(attr & AT_COLOR))
635 1.4 simonb {
636 1.4 simonb switch (attr)
637 1.4 simonb {
638 1.4 simonb case AT_NORMAL:
639 1.4 simonb colordesc(s, &nm_fg_color, &nm_bg_color);
640 1.4 simonb break;
641 1.4 simonb case AT_BOLD:
642 1.4 simonb colordesc(s, &bo_fg_color, &bo_bg_color);
643 1.4 simonb break;
644 1.4 simonb case AT_UNDERLINE:
645 1.4 simonb colordesc(s, &ul_fg_color, &ul_bg_color);
646 1.4 simonb break;
647 1.4 simonb case AT_BLINK:
648 1.4 simonb colordesc(s, &bl_fg_color, &bl_bg_color);
649 1.4 simonb break;
650 1.4 simonb case AT_STANDOUT:
651 1.4 simonb colordesc(s, &so_fg_color, &so_bg_color);
652 1.4 simonb break;
653 1.4 simonb }
654 1.4 simonb if (type == TOGGLE)
655 1.4 simonb {
656 1.4 simonb at_enter(AT_STANDOUT);
657 1.4 simonb at_exit();
658 1.4 simonb }
659 1.4 simonb } else
660 1.4 simonb #endif
661 1.4 simonb if (set_color_map(attr, s) < 0)
662 1.1 tron {
663 1.4 simonb p.p_string = s;
664 1.4 simonb error("Invalid color string \"%s\"", &p);
665 1.4 simonb return;
666 1.1 tron }
667 1.1 tron break;
668 1.4 simonb #if MSDOS_COMPILER
669 1.1 tron case QUERY:
670 1.4 simonb p.p_string = (sgr_mode) ? "on" : "off";
671 1.4 simonb error("SGR mode is %s", &p);
672 1.1 tron break;
673 1.4 simonb #endif
674 1.1 tron }
675 1.1 tron }
676 1.4 simonb
677 1.4 simonb /*
678 1.4 simonb */
679 1.4 simonb public void set_tabs(char *s, int len)
680 1.4 simonb {
681 1.4 simonb int i;
682 1.4 simonb char *es = s + len;
683 1.4 simonb /* Start at 1 because tabstops[0] is always zero. */
684 1.4 simonb for (i = 1; i < TABSTOP_MAX; )
685 1.4 simonb {
686 1.4 simonb int n = 0;
687 1.4 simonb int v = FALSE;
688 1.4 simonb while (s < es && *s == ' ')
689 1.4 simonb s++;
690 1.4 simonb for (; s < es && *s >= '0' && *s <= '9'; s++)
691 1.4 simonb {
692 1.4 simonb v |= ckd_mul(&n, n, 10);
693 1.4 simonb v |= ckd_add(&n, n, *s - '0');
694 1.4 simonb }
695 1.4 simonb if (!v && n > tabstops[i-1])
696 1.4 simonb tabstops[i++] = n;
697 1.4 simonb while (s < es && *s == ' ')
698 1.4 simonb s++;
699 1.4 simonb if (s == es || *s++ != ',')
700 1.4 simonb break;
701 1.4 simonb }
702 1.4 simonb if (i < 2)
703 1.4 simonb return;
704 1.4 simonb ntabstops = i;
705 1.4 simonb tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
706 1.4 simonb }
707 1.1 tron
708 1.1 tron /*
709 1.1 tron * Handler for the -x option.
710 1.1 tron */
711 1.4 simonb public void opt_x(int type, char *s)
712 1.4 simonb {
713 1.4 simonb char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)];
714 1.1 tron int i;
715 1.1 tron PARG p;
716 1.1 tron
717 1.1 tron switch (type)
718 1.1 tron {
719 1.1 tron case INIT:
720 1.1 tron case TOGGLE:
721 1.4 simonb set_tabs(s, strlen(s));
722 1.1 tron break;
723 1.1 tron case QUERY:
724 1.1 tron strcpy(msg, "Tab stops ");
725 1.1 tron if (ntabstops > 2)
726 1.1 tron {
727 1.1 tron for (i = 1; i < ntabstops; i++)
728 1.1 tron {
729 1.1 tron if (i > 1)
730 1.1 tron strcat(msg, ",");
731 1.1 tron sprintf(msg+strlen(msg), "%d", tabstops[i]);
732 1.1 tron }
733 1.1 tron sprintf(msg+strlen(msg), " and then ");
734 1.1 tron }
735 1.1 tron sprintf(msg+strlen(msg), "every %d spaces",
736 1.1 tron tabdefault);
737 1.1 tron p.p_string = msg;
738 1.1 tron error("%s", &p);
739 1.1 tron break;
740 1.1 tron }
741 1.1 tron }
742 1.1 tron
743 1.1 tron
744 1.1 tron /*
745 1.1 tron * Handler for the -" option.
746 1.1 tron */
747 1.4 simonb public void opt_quote(int type, char *s)
748 1.1 tron {
749 1.1 tron char buf[3];
750 1.1 tron PARG parg;
751 1.1 tron
752 1.1 tron switch (type)
753 1.1 tron {
754 1.1 tron case INIT:
755 1.1 tron case TOGGLE:
756 1.1 tron if (s[0] == '\0')
757 1.1 tron {
758 1.1 tron openquote = closequote = '\0';
759 1.1 tron break;
760 1.1 tron }
761 1.1 tron if (s[1] != '\0' && s[2] != '\0')
762 1.1 tron {
763 1.1 tron error("-\" must be followed by 1 or 2 chars", NULL_PARG);
764 1.1 tron return;
765 1.1 tron }
766 1.1 tron openquote = s[0];
767 1.1 tron if (s[1] == '\0')
768 1.1 tron closequote = openquote;
769 1.1 tron else
770 1.1 tron closequote = s[1];
771 1.1 tron break;
772 1.1 tron case QUERY:
773 1.1 tron buf[0] = openquote;
774 1.1 tron buf[1] = closequote;
775 1.1 tron buf[2] = '\0';
776 1.1 tron parg.p_string = buf;
777 1.1 tron error("quotes %s", &parg);
778 1.1 tron break;
779 1.1 tron }
780 1.1 tron }
781 1.1 tron
782 1.1 tron /*
783 1.4 simonb * Handler for the --rscroll option.
784 1.4 simonb */
785 1.4 simonb /*ARGSUSED*/
786 1.4 simonb public void opt_rscroll(int type, char *s)
787 1.4 simonb {
788 1.4 simonb PARG p;
789 1.4 simonb
790 1.4 simonb switch (type)
791 1.4 simonb {
792 1.4 simonb case INIT:
793 1.4 simonb case TOGGLE: {
794 1.4 simonb char *fmt;
795 1.4 simonb int attr = AT_STANDOUT;
796 1.4 simonb setfmt(s, &fmt, &attr, "*s>", FALSE);
797 1.4 simonb if (strcmp(fmt, "-") == 0)
798 1.4 simonb {
799 1.4 simonb rscroll_char = 0;
800 1.4 simonb } else
801 1.4 simonb {
802 1.4 simonb rscroll_char = *fmt ? *fmt : '>';
803 1.4 simonb rscroll_attr = attr|AT_COLOR_RSCROLL;
804 1.4 simonb }
805 1.4 simonb break; }
806 1.4 simonb case QUERY: {
807 1.4 simonb p.p_string = rscroll_char ? prchar(rscroll_char) : "-";
808 1.4 simonb error("rscroll character is %s", &p);
809 1.4 simonb break; }
810 1.4 simonb }
811 1.4 simonb }
812 1.4 simonb
813 1.4 simonb /*
814 1.1 tron * "-?" means display a help message.
815 1.1 tron * If from the command line, exit immediately.
816 1.1 tron */
817 1.1 tron /*ARGSUSED*/
818 1.4 simonb public void opt_query(int type, char *s)
819 1.1 tron {
820 1.1 tron switch (type)
821 1.1 tron {
822 1.1 tron case QUERY:
823 1.1 tron case TOGGLE:
824 1.1 tron error("Use \"h\" for help", NULL_PARG);
825 1.1 tron break;
826 1.1 tron case INIT:
827 1.1 tron dohelp = 1;
828 1.1 tron }
829 1.1 tron }
830 1.1 tron
831 1.1 tron /*
832 1.4 simonb * Handler for the --mouse option.
833 1.4 simonb */
834 1.4 simonb /*ARGSUSED*/
835 1.4 simonb public void opt_mousecap(int type, char *s)
836 1.4 simonb {
837 1.4 simonb switch (type)
838 1.4 simonb {
839 1.4 simonb case TOGGLE:
840 1.4 simonb if (mousecap == OPT_OFF)
841 1.4 simonb deinit_mouse();
842 1.4 simonb else
843 1.4 simonb init_mouse();
844 1.4 simonb break;
845 1.4 simonb case INIT:
846 1.4 simonb case QUERY:
847 1.4 simonb break;
848 1.4 simonb }
849 1.4 simonb }
850 1.4 simonb
851 1.4 simonb /*
852 1.4 simonb * Handler for the --wheel-lines option.
853 1.4 simonb */
854 1.4 simonb /*ARGSUSED*/
855 1.4 simonb public void opt_wheel_lines(int type, char *s)
856 1.4 simonb {
857 1.4 simonb switch (type)
858 1.4 simonb {
859 1.4 simonb case INIT:
860 1.4 simonb case TOGGLE:
861 1.4 simonb if (wheel_lines <= 0)
862 1.4 simonb wheel_lines = default_wheel_lines();
863 1.4 simonb break;
864 1.4 simonb case QUERY:
865 1.4 simonb break;
866 1.4 simonb }
867 1.4 simonb }
868 1.4 simonb
869 1.4 simonb /*
870 1.4 simonb * Handler for the --line-number-width option.
871 1.4 simonb */
872 1.4 simonb /*ARGSUSED*/
873 1.4 simonb public void opt_linenum_width(int type, char *s)
874 1.4 simonb {
875 1.4 simonb PARG parg;
876 1.4 simonb
877 1.4 simonb switch (type)
878 1.4 simonb {
879 1.4 simonb case INIT:
880 1.4 simonb case TOGGLE:
881 1.4 simonb if (linenum_width > MAX_LINENUM_WIDTH)
882 1.4 simonb {
883 1.4 simonb parg.p_int = MAX_LINENUM_WIDTH;
884 1.4 simonb error("Line number width must not be larger than %d", &parg);
885 1.4 simonb linenum_width = MIN_LINENUM_WIDTH;
886 1.4 simonb }
887 1.4 simonb break;
888 1.4 simonb case QUERY:
889 1.4 simonb break;
890 1.4 simonb }
891 1.4 simonb }
892 1.4 simonb
893 1.4 simonb /*
894 1.4 simonb * Handler for the --status-column-width option.
895 1.4 simonb */
896 1.4 simonb /*ARGSUSED*/
897 1.4 simonb public void opt_status_col_width(int type, char *s)
898 1.4 simonb {
899 1.4 simonb PARG parg;
900 1.4 simonb
901 1.4 simonb switch (type)
902 1.4 simonb {
903 1.4 simonb case INIT:
904 1.4 simonb case TOGGLE:
905 1.4 simonb if (status_col_width > MAX_STATUSCOL_WIDTH)
906 1.4 simonb {
907 1.4 simonb parg.p_int = MAX_STATUSCOL_WIDTH;
908 1.4 simonb error("Status column width must not be larger than %d", &parg);
909 1.4 simonb status_col_width = 2;
910 1.4 simonb }
911 1.4 simonb break;
912 1.4 simonb case QUERY:
913 1.4 simonb break;
914 1.4 simonb }
915 1.4 simonb }
916 1.4 simonb
917 1.4 simonb /*
918 1.4 simonb * Handler for the --file-size option.
919 1.4 simonb */
920 1.4 simonb /*ARGSUSED*/
921 1.4 simonb public void opt_filesize(int type, char *s)
922 1.4 simonb {
923 1.4 simonb switch (type)
924 1.4 simonb {
925 1.4 simonb case INIT:
926 1.4 simonb case TOGGLE:
927 1.4 simonb if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION)
928 1.4 simonb scan_eof();
929 1.4 simonb break;
930 1.4 simonb case QUERY:
931 1.4 simonb break;
932 1.4 simonb }
933 1.4 simonb }
934 1.4 simonb
935 1.4 simonb /*
936 1.4 simonb * Handler for the --intr option.
937 1.4 simonb */
938 1.4 simonb /*ARGSUSED*/
939 1.4 simonb public void opt_intr(int type, char *s)
940 1.4 simonb {
941 1.4 simonb PARG p;
942 1.4 simonb
943 1.4 simonb switch (type)
944 1.4 simonb {
945 1.4 simonb case INIT:
946 1.4 simonb case TOGGLE:
947 1.4 simonb intr_char = *s;
948 1.4 simonb if (intr_char == '^' && s[1] != '\0')
949 1.4 simonb intr_char = CONTROL(s[1]);
950 1.4 simonb break;
951 1.4 simonb case QUERY: {
952 1.4 simonb p.p_string = prchar(intr_char);
953 1.4 simonb error("interrupt character is %s", &p);
954 1.4 simonb break; }
955 1.4 simonb }
956 1.4 simonb }
957 1.4 simonb
958 1.4 simonb /*
959 1.4 simonb * Handler for the --header option.
960 1.4 simonb */
961 1.4 simonb /*ARGSUSED*/
962 1.4 simonb public void opt_header(int type, char *s)
963 1.4 simonb {
964 1.4 simonb int err;
965 1.4 simonb int n;
966 1.4 simonb
967 1.4 simonb switch (type)
968 1.4 simonb {
969 1.4 simonb case INIT:
970 1.4 simonb case TOGGLE:
971 1.4 simonb header_lines = 0;
972 1.4 simonb header_cols = 0;
973 1.4 simonb if (*s != ',')
974 1.4 simonb {
975 1.4 simonb n = getnum(&s, "header", &err);
976 1.4 simonb if (err)
977 1.4 simonb {
978 1.4 simonb error("invalid number of lines", NULL_PARG);
979 1.4 simonb return;
980 1.4 simonb }
981 1.4 simonb header_lines = n;
982 1.4 simonb }
983 1.4 simonb if (*s == ',')
984 1.4 simonb {
985 1.4 simonb ++s;
986 1.4 simonb n = getnum(&s, "header", &err);
987 1.4 simonb if (err)
988 1.4 simonb error("invalid number of columns", NULL_PARG);
989 1.4 simonb else
990 1.4 simonb header_cols = n;
991 1.4 simonb }
992 1.4 simonb break;
993 1.4 simonb case QUERY:
994 1.4 simonb {
995 1.4 simonb char buf[2*INT_STRLEN_BOUND(int)+2];
996 1.4 simonb PARG parg;
997 1.4 simonb SNPRINTF2(buf, sizeof(buf), "%d,%d", header_lines, header_cols);
998 1.4 simonb parg.p_string = buf;
999 1.4 simonb error("header (lines,columns) is %s", &parg);
1000 1.4 simonb }
1001 1.4 simonb break;
1002 1.4 simonb }
1003 1.4 simonb }
1004 1.4 simonb
1005 1.4 simonb /*
1006 1.4 simonb * Handler for the --search-options option.
1007 1.4 simonb */
1008 1.4 simonb /*ARGSUSED*/
1009 1.4 simonb public void opt_search_type(int type, char *s)
1010 1.4 simonb {
1011 1.4 simonb int st;
1012 1.4 simonb PARG parg;
1013 1.4 simonb char buf[16];
1014 1.4 simonb char *bp;
1015 1.4 simonb int i;
1016 1.4 simonb
1017 1.4 simonb switch (type)
1018 1.4 simonb {
1019 1.4 simonb case INIT:
1020 1.4 simonb case TOGGLE:
1021 1.4 simonb st = 0;
1022 1.4 simonb for (; *s != '\0'; s++)
1023 1.4 simonb {
1024 1.4 simonb switch (*s)
1025 1.4 simonb {
1026 1.4 simonb case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF; break;
1027 1.4 simonb case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break;
1028 1.4 simonb case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE; break;
1029 1.4 simonb case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH; break;
1030 1.4 simonb case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX; break;
1031 1.4 simonb case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP; break;
1032 1.4 simonb case '-': st = 0; break;
1033 1.4 simonb case '^': break;
1034 1.4 simonb default:
1035 1.4 simonb if (*s >= '1' && *s <= '0'+NUM_SEARCH_COLORS)
1036 1.4 simonb {
1037 1.4 simonb st |= SRCH_SUBSEARCH(*s-'0');
1038 1.4 simonb break;
1039 1.4 simonb }
1040 1.4 simonb parg.p_char = *s;
1041 1.4 simonb error("invalid search option '%c'", &parg);
1042 1.4 simonb return;
1043 1.4 simonb }
1044 1.4 simonb }
1045 1.4 simonb def_search_type = norm_search_type(st);
1046 1.4 simonb break;
1047 1.4 simonb case QUERY:
1048 1.4 simonb bp = buf;
1049 1.4 simonb if (def_search_type & SRCH_PAST_EOF) *bp++ = 'E';
1050 1.4 simonb if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F';
1051 1.4 simonb if (def_search_type & SRCH_NO_MOVE) *bp++ = 'K';
1052 1.4 simonb if (def_search_type & SRCH_NO_MATCH) *bp++ = 'N';
1053 1.4 simonb if (def_search_type & SRCH_NO_REGEX) *bp++ = 'R';
1054 1.4 simonb if (def_search_type & SRCH_WRAP) *bp++ = 'W';
1055 1.4 simonb for (i = 1; i <= NUM_SEARCH_COLORS; i++)
1056 1.4 simonb if (def_search_type & SRCH_SUBSEARCH(i))
1057 1.4 simonb *bp++ = '0'+i;
1058 1.4 simonb if (bp == buf)
1059 1.4 simonb *bp++ = '-';
1060 1.4 simonb *bp = '\0';
1061 1.4 simonb parg.p_string = buf;
1062 1.4 simonb error("search options: %s", &parg);
1063 1.4 simonb break;
1064 1.4 simonb }
1065 1.4 simonb }
1066 1.4 simonb
1067 1.4 simonb #if LESSTEST
1068 1.4 simonb /*
1069 1.4 simonb * Handler for the --tty option.
1070 1.4 simonb */
1071 1.4 simonb /*ARGSUSED*/
1072 1.4 simonb public void opt_ttyin_name(int type, char *s)
1073 1.4 simonb {
1074 1.4 simonb switch (type)
1075 1.4 simonb {
1076 1.4 simonb case INIT:
1077 1.4 simonb ttyin_name = s;
1078 1.4 simonb is_tty = 1;
1079 1.4 simonb break;
1080 1.4 simonb }
1081 1.4 simonb }
1082 1.4 simonb #endif /*LESSTEST*/
1083 1.4 simonb
1084 1.4 simonb public int chop_line(void)
1085 1.4 simonb {
1086 1.4 simonb return (chopline || header_cols > 0 || header_lines > 0);
1087 1.4 simonb }
1088 1.4 simonb
1089 1.4 simonb /*
1090 1.1 tron * Get the "screen window" size.
1091 1.1 tron */
1092 1.4 simonb public int get_swindow(void)
1093 1.1 tron {
1094 1.1 tron if (swindow > 0)
1095 1.1 tron return (swindow);
1096 1.4 simonb return (sc_height - header_lines + swindow);
1097 1.1 tron }
1098 1.1 tron
1099