1/*
2 * Copyright (C) 1984-2023  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#define NEWBOT 1
11
12/*
13 * Standard include file for "less".
14 */
15
16/*
17 * Defines for MSDOS_COMPILER.
18 */
19#define MSOFTC          1   /* Microsoft C */
20#define BORLANDC        2   /* Borland C */
21#define WIN32C          3   /* Windows (Borland C or Microsoft C) */
22#define DJGPPC          4   /* DJGPP C */
23
24/*
25 * Include the file of compile-time options.
26 * The <> make cc search for it in -I., not srcdir.
27 */
28#include <defines.h>
29
30#ifdef _SEQUENT_
31/*
32 * Kludge for Sequent Dynix systems that have sigsetmask, but
33 * it's not compatible with the way less calls it.
34 * {{ Do other systems need this? }}
35 */
36#undef HAVE_SIGSETMASK
37#endif
38
39/*
40 * Language details.
41 */
42#if HAVE_CONST
43#define constant        const
44#else
45#define constant
46#endif
47
48#define public          /* PUBLIC FUNCTION */
49
50/* Library function declarations */
51
52#if HAVE_SYS_TYPES_H
53#include <sys/types.h>
54#endif
55#if HAVE_STDIO_H
56#include <stdio.h>
57#endif
58#if HAVE_FCNTL_H
59#include <fcntl.h>
60#endif
61#if HAVE_UNISTD_H
62#include <unistd.h>
63#endif
64#if HAVE_CTYPE_H
65#include <ctype.h>
66#endif
67#if HAVE_WCTYPE_H
68#include <wctype.h>
69#endif
70#if HAVE_LIMITS_H
71#include <limits.h>
72#endif
73#if HAVE_STDINT_H
74#include <stdint.h>
75#endif
76#if HAVE_STDLIB_H
77#include <stdlib.h>
78#endif
79#if HAVE_STRING_H
80#include <string.h>
81#endif
82
83#if HAVE_STDCKDINT_H
84#include <stdckdint.h>
85#else
86/*
87 * These substitutes for C23 stdckdint macros do not set *R on overflow,
88 * and they assume A and B are nonnegative.  That is good enough for us.
89 */
90#define ckd_add(r, a, b) help_ckd_add(r, a, b, sizeof *(r), signed_expr(*(r)))
91#define ckd_mul(r, a, b) help_ckd_mul(r, a, b, sizeof *(r), signed_expr(*(r)))
92/* True if the integer expression E, after promotion, is signed.  */
93#define signed_expr(e) ((TRUE ? 0 : e) - 1 < 0)
94#endif
95
96#if defined UINTMAX_MAX
97typedef uintmax_t uintmax;
98#elif defined ULLONG_MAX
99typedef unsigned long long uintmax;
100#else
101typedef unsigned long uintmax;
102#endif
103
104/* OS-specific includes */
105#ifdef _OSK
106#include <modes.h>
107#include <strings.h>
108#endif
109
110#ifdef __TANDEM
111#include <floss.h>
112#endif
113
114#if MSDOS_COMPILER==WIN32C || OS2
115#include <io.h>
116#endif
117
118#if MSDOS_COMPILER==DJGPPC
119#include <io.h>
120#include <sys/exceptn.h>
121#include <conio.h>
122#include <pc.h>
123#endif
124
125#if !HAVE_STDLIB_H
126char *getenv();
127off_t lseek();
128void *calloc();
129void free();
130#endif
131
132/*
133 * Simple lowercase test which can be used during option processing
134 * (before options are parsed which might tell us what charset to use).
135 */
136#define ASCII_IS_UPPER(c)       ((c) >= 'A' && (c) <= 'Z')
137#define ASCII_IS_LOWER(c)       ((c) >= 'a' && (c) <= 'z')
138#define ASCII_TO_UPPER(c)       ((c) - 'a' + 'A')
139#define ASCII_TO_LOWER(c)       ((c) - 'A' + 'a')
140
141#undef IS_UPPER
142#undef IS_LOWER
143#undef TO_UPPER
144#undef TO_LOWER
145#undef IS_SPACE
146#undef IS_DIGIT
147
148#if HAVE_WCTYPE
149#define IS_UPPER(c)     iswupper(c)
150#define IS_LOWER(c)     iswlower(c)
151#define TO_UPPER(c)     towupper(c)
152#define TO_LOWER(c)     towlower(c)
153#else
154#if HAVE_UPPER_LOWER
155#define IS_UPPER(c)     isupper((unsigned char) (c))
156#define IS_LOWER(c)     islower((unsigned char) (c))
157#define TO_UPPER(c)     toupper((unsigned char) (c))
158#define TO_LOWER(c)     tolower((unsigned char) (c))
159#else
160#define IS_UPPER(c)     ASCII_IS_UPPER(c)
161#define IS_LOWER(c)     ASCII_IS_LOWER(c)
162#define TO_UPPER(c)     ASCII_TO_UPPER(c)
163#define TO_LOWER(c)     ASCII_TO_LOWER(c)
164#endif
165#endif
166
167#ifdef isspace
168#define IS_SPACE(c)     isspace((unsigned char)(c))
169#else
170#define IS_SPACE(c)     ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == '\f')
171#endif
172
173#ifdef isdigit
174#define IS_DIGIT(c)     isdigit((unsigned char)(c))
175#else
176#define IS_DIGIT(c)     ((c) >= '0' && (c) <= '9')
177#endif
178
179#define IS_CSI_START(c) (((LWCHAR)(c)) == ESC || (((LWCHAR)(c)) == CSI))
180
181#ifndef NULL
182#define NULL    0
183#endif
184
185#ifndef TRUE
186#define TRUE            1
187#endif
188#ifndef FALSE
189#define FALSE           0
190#endif
191
192#define OPT_OFF         0
193#define OPT_ON          1
194#define OPT_ONPLUS      2
195
196#if !HAVE_MEMCPY
197#ifndef memcpy
198#define memcpy(to,from,len)     bcopy((from),(to),(len))
199#endif
200#endif
201
202#if HAVE_SNPRINTF
203#define SNPRINTF1(str, size, fmt, v1)             snprintf((str), (size), (fmt), (v1))
204#define SNPRINTF2(str, size, fmt, v1, v2)         snprintf((str), (size), (fmt), (v1), (v2))
205#define SNPRINTF3(str, size, fmt, v1, v2, v3)     snprintf((str), (size), (fmt), (v1), (v2), (v3))
206#define SNPRINTF4(str, size, fmt, v1, v2, v3, v4) snprintf((str), (size), (fmt), (v1), (v2), (v3), (v4))
207#else
208/* Use unsafe sprintf if we don't have snprintf. */
209#define SNPRINTF1(str, size, fmt, v1)             sprintf((str), (fmt), (v1))
210#define SNPRINTF2(str, size, fmt, v1, v2)         sprintf((str), (fmt), (v1), (v2))
211#define SNPRINTF3(str, size, fmt, v1, v2, v3)     sprintf((str), (fmt), (v1), (v2), (v3))
212#define SNPRINTF4(str, size, fmt, v1, v2, v3, v4) sprintf((str), (fmt), (v1), (v2), (v3), (v4))
213#endif
214
215#define BAD_LSEEK       ((off_t)-1)
216
217#ifndef SEEK_SET
218#define SEEK_SET 0
219#endif
220#ifndef SEEK_END
221#define SEEK_END 2
222#endif
223
224#ifndef CHAR_BIT
225#define CHAR_BIT 8
226#endif
227
228/*
229 * Upper bound on the string length of an integer converted to string.
230 * 302 / 1000 is ceil (log10 (2.0)).  Subtract 1 for the sign bit;
231 * add 1 for integer division truncation; add 1 more for a minus sign.
232 */
233#define INT_STRLEN_BOUND(t) ((sizeof(t) * CHAR_BIT - 1) * 302 / 1000 + 1 + 1)
234
235/*
236 * Special types and constants.
237 */
238typedef unsigned long LWCHAR;
239typedef off_t           POSITION;
240typedef off_t           LINENUM;
241#define MIN_LINENUM_WIDTH   7   /* Default min printing width of a line number */
242#define MAX_LINENUM_WIDTH   16  /* Max width of a line number */
243#define MAX_STATUSCOL_WIDTH 4   /* Max width of the status column */
244#define MAX_UTF_CHAR_LEN    6   /* Max bytes in one UTF-8 char */
245#define MAX_PRCHAR_LEN      31  /* Max chars in prchar() result */
246
247#define NULL_POSITION   ((POSITION)(-1))
248
249/*
250 * Flags for open()
251 */
252#if MSDOS_COMPILER || OS2
253#define OPEN_READ       (O_RDONLY|O_BINARY)
254#else
255#ifdef _OSK
256#define OPEN_READ       (S_IREAD)
257#else
258#ifdef O_RDONLY
259#define OPEN_READ       (O_RDONLY)
260#else
261#define OPEN_READ       (0)
262#endif
263#endif
264#endif
265
266#if defined(O_WRONLY) && defined(O_APPEND)
267#define OPEN_APPEND     (O_APPEND|O_WRONLY)
268#else
269#ifdef _OSK
270#define OPEN_APPEND     (S_IWRITE)
271#else
272#define OPEN_APPEND     (1)
273#endif
274#endif
275
276/*
277 * Flags for creat()
278 */
279#if MSDOS_COMPILER
280#define CREAT_RW        (S_IREAD|S_IWRITE)
281#else
282#define CREAT_RW        0644
283#endif
284
285/*
286 * Set a file descriptor to binary mode.
287 */
288#if MSDOS_COMPILER==MSOFTC
289#define SET_BINARY(f)   _setmode(f, _O_BINARY);
290#else
291#if MSDOS_COMPILER || OS2
292#define SET_BINARY(f)   setmode(f, O_BINARY)
293#else
294#define SET_BINARY(f)
295#endif
296#endif
297
298/*
299 * Does the shell treat "?" as a metacharacter?
300 */
301#if MSDOS_COMPILER || OS2 || _OSK
302#define SHELL_META_QUEST 0
303#else
304#define SHELL_META_QUEST 1
305#endif
306
307#define SPACES_IN_FILENAMES 1
308
309/*
310 * An IFILE represents an input file.
311 */
312#define IFILE           void*
313#define NULL_IFILE      ((IFILE)NULL)
314
315/*
316 * The structure used to represent a "screen position".
317 * This consists of a file position, and a screen line number.
318 * The meaning is that the line starting at the given file
319 * position is displayed on the ln-th line of the screen.
320 * (Screen lines before ln are empty.)
321 */
322struct scrpos
323{
324        POSITION pos;
325        int ln;
326};
327
328typedef union parg
329{
330        char *p_string;
331        int p_int;
332        LINENUM p_linenum;
333        char p_char;
334} PARG;
335
336#define NULL_PARG       ((PARG *)NULL)
337
338struct textlist
339{
340        char *string;
341        char *endstring;
342};
343
344struct wchar_range
345{
346        LWCHAR first, last;
347};
348
349struct wchar_range_table
350{
351        struct wchar_range *table;
352        int count;
353};
354
355#if HAVE_POLL
356typedef short POLL_EVENTS;
357#endif
358
359#define EOI             (-1)
360
361#define READ_ERR        (-1)
362#define READ_INTR       (-2)
363#define READ_AGAIN      (-3)
364
365/*
366 * A fraction is represented by a long n; the fraction is n/NUM_FRAC_DENOM.
367 * To avoid overflow problems, 0 <= n < NUM_FRAC_DENUM <= LONG_MAX/100.
368 */
369#define NUM_FRAC_DENOM                  1000000
370#define NUM_LOG_FRAC_DENOM              6
371
372/* How quiet should we be? */
373#define NOT_QUIET       0       /* Ring bell at eof and for errors */
374#define LITTLE_QUIET    1       /* Ring bell only for errors */
375#define VERY_QUIET      2       /* Never ring bell */
376
377/* How should we prompt? */
378#define PR_SHORT        0       /* Prompt with colon */
379#define PR_MEDIUM       1       /* Prompt with message */
380#define PR_LONG         2       /* Prompt with longer message */
381
382/* How should we handle backspaces? */
383#define BS_SPECIAL      0       /* Do special things for underlining and bold */
384#define BS_NORMAL       1       /* \b treated as normal char; actually output */
385#define BS_CONTROL      2       /* \b treated as control char; prints as ^H */
386
387/* How should we search? */
388#define SRCH_FORW       (1 << 0)  /* Search forward from current position */
389#define SRCH_BACK       (1 << 1)  /* Search backward from current position */
390#define SRCH_NO_MOVE    (1 << 2)  /* Highlight, but don't move */
391#define SRCH_INCR       (1 << 3)  /* Incremental search */
392#define SRCH_FIND_ALL   (1 << 4)  /* Find and highlight all matches */
393#define SRCH_NO_MATCH   (1 << 8)  /* Search for non-matching lines */
394#define SRCH_PAST_EOF   (1 << 9)  /* Search past end-of-file, into next file */
395#define SRCH_FIRST_FILE (1 << 10) /* Search starting at the first file */
396#define SRCH_NO_REGEX   (1 << 12) /* Don't use regular expressions */
397#define SRCH_FILTER     (1 << 13) /* Search is for '&' (filter) command */
398#define SRCH_AFTER_TARGET (1 << 14) /* Start search after the target line */
399#define SRCH_WRAP       (1 << 15) /* Wrap-around search (continue at BOF/EOF) */
400#define SRCH_SUBSEARCH(i) (1 << (16+(i))) /* Search for subpattern */
401/* {{ Depends on NUM_SEARCH_COLORS==5 }} */
402#define SRCH_SUBSEARCH_ALL (SRCH_SUBSEARCH(1)|SRCH_SUBSEARCH(2)|SRCH_SUBSEARCH(3)|SRCH_SUBSEARCH(4)|SRCH_SUBSEARCH(5))
403
404#define SRCH_REVERSE(t) (((t) & SRCH_FORW) ? \
405                                (((t) & ~SRCH_FORW) | SRCH_BACK) : \
406                                (((t) & ~SRCH_BACK) | SRCH_FORW))
407
408/* */
409#define NO_MCA          0
410#define MCA_DONE        1
411#define MCA_MORE        2
412
413#define CC_OK           0       /* Char was accepted & processed */
414#define CC_QUIT         1       /* Char was a request to abort current cmd */
415#define CC_ERROR        2       /* Char could not be accepted due to error */
416#define CC_PASS         3       /* Char was rejected (internal) */
417
418#define CF_QUIT_ON_ERASE 0001   /* Abort cmd if its entirely erased */
419
420/* Special char bit-flags used to tell put_line() to do something special */
421#define AT_NORMAL       (0)
422#define AT_UNDERLINE    (1 << 0)
423#define AT_BOLD         (1 << 1)
424#define AT_BLINK        (1 << 2)
425#define AT_STANDOUT     (1 << 3)
426#define AT_ANSI         (1 << 4)  /* Content-supplied "ANSI" escape sequence */
427#define AT_BINARY       (1 << 5)  /* LESS*BINFMT representation */
428#define AT_HILITE       (1 << 6)  /* Internal highlights (e.g., for search) */
429
430#define AT_COLOR_SHIFT    8
431#define AT_NUM_COLORS     16
432#define AT_COLOR          ((AT_NUM_COLORS-1) << AT_COLOR_SHIFT)
433#define AT_COLOR_ATTN     (1 << AT_COLOR_SHIFT)
434#define AT_COLOR_BIN      (2 << AT_COLOR_SHIFT)
435#define AT_COLOR_CTRL     (3 << AT_COLOR_SHIFT)
436#define AT_COLOR_ERROR    (4 << AT_COLOR_SHIFT)
437#define AT_COLOR_LINENUM  (5 << AT_COLOR_SHIFT)
438#define AT_COLOR_MARK     (6 << AT_COLOR_SHIFT)
439#define AT_COLOR_PROMPT   (7 << AT_COLOR_SHIFT)
440#define AT_COLOR_RSCROLL  (8 << AT_COLOR_SHIFT)
441#define AT_COLOR_HEADER   (9 << AT_COLOR_SHIFT)
442#define AT_COLOR_SEARCH   (10 << AT_COLOR_SHIFT)
443#define AT_COLOR_SUBSEARCH(i) ((10+(i)) << AT_COLOR_SHIFT)
444#define NUM_SEARCH_COLORS (AT_NUM_COLORS-10-1)
445
446typedef enum { CT_NULL, CT_4BIT, CT_6BIT } COLOR_TYPE;
447
448typedef enum {
449	CV_BLUE     = 1,
450	CV_GREEN    = 2,
451	CV_RED      = 4,
452	CV_BRIGHT   = 8,
453	CV_NOCHANGE = -2,
454	CV_ERROR    = -1
455} COLOR_VALUE;
456
457/* ANSI states */
458#define ANSI_MID    1
459#define ANSI_ERR    2
460#define ANSI_END    3
461
462#if '0' == 240
463#define IS_EBCDIC_HOST 1
464#endif
465
466#if IS_EBCDIC_HOST
467/*
468 * Long definition for EBCDIC.
469 * Since the argument is usually a constant, this macro normally compiles
470 * into a constant.
471 */
472#define CONTROL(c) ( \
473        (c)=='[' ? '\047' : \
474        (c)=='a' ? '\001' : \
475        (c)=='b' ? '\002' : \
476        (c)=='c' ? '\003' : \
477        (c)=='d' ? '\067' : \
478        (c)=='e' ? '\055' : \
479        (c)=='f' ? '\056' : \
480        (c)=='g' ? '\057' : \
481        (c)=='h' ? '\026' : \
482        (c)=='i' ? '\005' : \
483        (c)=='j' ? '\025' : \
484        (c)=='k' ? '\013' : \
485        (c)=='l' ? '\014' : \
486        (c)=='m' ? '\015' : \
487        (c)=='n' ? '\016' : \
488        (c)=='o' ? '\017' : \
489        (c)=='p' ? '\020' : \
490        (c)=='q' ? '\021' : \
491        (c)=='r' ? '\022' : \
492        (c)=='s' ? '\023' : \
493        (c)=='t' ? '\074' : \
494        (c)=='u' ? '\075' : \
495        (c)=='v' ? '\062' : \
496        (c)=='w' ? '\046' : \
497        (c)=='x' ? '\030' : \
498        (c)=='y' ? '\031' : \
499        (c)=='z' ? '\077' : \
500        (c)=='A' ? '\001' : \
501        (c)=='B' ? '\002' : \
502        (c)=='C' ? '\003' : \
503        (c)=='D' ? '\067' : \
504        (c)=='E' ? '\055' : \
505        (c)=='F' ? '\056' : \
506        (c)=='G' ? '\057' : \
507        (c)=='H' ? '\026' : \
508        (c)=='I' ? '\005' : \
509        (c)=='J' ? '\025' : \
510        (c)=='K' ? '\013' : \
511        (c)=='L' ? '\014' : \
512        (c)=='M' ? '\015' : \
513        (c)=='N' ? '\016' : \
514        (c)=='O' ? '\017' : \
515        (c)=='P' ? '\020' : \
516        (c)=='Q' ? '\021' : \
517        (c)=='R' ? '\022' : \
518        (c)=='S' ? '\023' : \
519        (c)=='T' ? '\074' : \
520        (c)=='U' ? '\075' : \
521        (c)=='V' ? '\062' : \
522        (c)=='W' ? '\046' : \
523        (c)=='X' ? '\030' : \
524        (c)=='Y' ? '\031' : \
525        (c)=='Z' ? '\077' : \
526        (c)=='|' ? '\031' : \
527        (c)=='\\' ? '\034' : \
528        (c)=='^' ? '\036' : \
529        (c)&077)
530#else
531#define CONTROL(c)      ((c)&037)
532#endif /* IS_EBCDIC_HOST */
533
534#define ESC             CONTROL('[')
535#define ESCS            "\33"
536#define CSI             ((unsigned char)'\233')
537#define CHAR_END_COMMAND 0x40000000
538
539#if _OSK_MWC32
540#define LSIGNAL(sig,func)       os9_signal(sig,func)
541#else
542#define LSIGNAL(sig,func)       signal(sig,func)
543#endif
544
545#if HAVE_SIGPROCMASK
546#if HAVE_SIGSET_T
547#else
548#undef HAVE_SIGPROCMASK
549#endif
550#endif
551#if HAVE_SIGPROCMASK
552#if HAVE_SIGEMPTYSET
553#else
554#undef  sigemptyset
555#define sigemptyset(mp) *(mp) = 0
556#endif
557#endif
558
559#define S_INTERRUPT     01
560#define S_STOP          02
561#define S_WINCH         04
562#define ABORT_SIGS()    (sigs & (S_INTERRUPT|S_STOP))
563
564#ifdef EXIT_SUCCESS
565#define QUIT_OK         EXIT_SUCCESS
566#else
567#define QUIT_OK         0
568#endif
569#ifdef EXIT_FAILURE
570#define QUIT_ERROR      EXIT_FAILURE
571#define QUIT_INTERRUPT  (EXIT_FAILURE+1)
572#else
573#define QUIT_ERROR      1
574#define QUIT_INTERRUPT  2
575#endif
576#define QUIT_SAVED_STATUS (-1)
577
578#define FOLLOW_DESC     0
579#define FOLLOW_NAME     1
580
581/* filestate flags */
582#define CH_CANSEEK      001
583#define CH_KEEPOPEN     002
584#define CH_POPENED      004
585#define CH_HELPFILE     010
586#define CH_NODATA       020     /* Special case for zero length files */
587
588#define ch_zero()       ((POSITION)0)
589
590#define FAKE_HELPFILE   "@/\\less/\\help/\\file/\\@"
591#define FAKE_EMPTYFILE  "@/\\less/\\empty/\\file/\\@"
592
593/* Flags for cvt_text */
594#define CVT_TO_LC       01      /* Convert upper-case to lower-case */
595#define CVT_BS          02      /* Do backspace processing */
596#define CVT_CRLF        04      /* Remove CR after LF */
597#define CVT_ANSI        010     /* Remove ANSI escape sequences */
598
599#if HAVE_TIME_T
600#define time_type       time_t
601#else
602#define time_type       long
603#endif
604
605/* X11 mouse reporting definitions */
606#define X11MOUSE_BUTTON1    0 /* Left button press */
607#define X11MOUSE_BUTTON2    1 /* Middle button press */
608#define X11MOUSE_BUTTON3    2 /* Right button press */
609#define X11MOUSE_BUTTON_REL 3 /* Button release */
610#define X11MOUSE_WHEEL_UP   0x40 /* Wheel scroll up */
611#define X11MOUSE_WHEEL_DOWN 0x41 /* Wheel scroll down */
612#define X11MOUSE_OFFSET     0x20 /* Added to button & pos bytes to create a char */
613
614#if LESSTEST
615#define LESS_DUMP_CHAR CONTROL(']')
616#endif
617
618struct mlist;
619struct loption;
620struct hilite_tree;
621struct ansi_state;
622#include "pattern.h"
623#include "xbuf.h"
624#include "funcs.h"
625
626/* Functions not included in funcs.h */
627void postoa(POSITION, char*, int);
628void linenumtoa(LINENUM, char*, int);
629void inttoa(int, char*, int);
630int lstrtoi(char*, char**, int);
631POSITION lstrtopos(char*, char**, int);
632unsigned long lstrtoul(char*, char**, int);
633#if MSDOS_COMPILER==WIN32C
634int pclose(FILE*);
635#endif
636