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