Merge from vendor branch NTPD:
[dragonfly.git] / contrib / less-381 / main.c
1 /*
2  * Copyright (C) 1984-2002  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 about less, or for information on how to 
8  * contact the author, see the README file.
9  */
10
11
12 /*
13  * Entry point, initialization, miscellaneous routines.
14  */
15
16 #include "less.h"
17 #if MSDOS_COMPILER==WIN32C
18 #include <windows.h>
19 #endif
20
21 public char *   every_first_cmd = NULL;
22 public int      new_file;
23 public int      is_tty;
24 public IFILE    curr_ifile = NULL_IFILE;
25 public IFILE    old_ifile = NULL_IFILE;
26 public struct scrpos initial_scrpos;
27 public int      any_display = FALSE;
28 public POSITION start_attnpos = NULL_POSITION;
29 public POSITION end_attnpos = NULL_POSITION;
30 public int      wscroll;
31 public char *   progname;
32 public int      quitting;
33 public int      secure;
34 public int      dohelp;
35
36 #if LOGFILE
37 public int      logfile = -1;
38 public int      force_logfile = FALSE;
39 public char *   namelogfile = NULL;
40 #endif
41
42 #if EDITOR
43 public char *   editor;
44 public char *   editproto;
45 #endif
46
47 #if TAGS
48 extern char *   tags;
49 extern char *   tagoption;
50 extern int      jump_sline;
51 #endif
52
53 #ifdef WIN32
54 static char consoleTitle[256];
55 #endif
56
57 extern int      missing_cap;
58 extern int      know_dumb;
59
60
61 /*
62  * Entry point.
63  */
64 int
65 main(argc, argv)
66         int argc;
67         char *argv[];
68 {
69         IFILE ifile;
70         char *s;
71
72 #ifdef __EMX__
73         _response(&argc, &argv);
74         _wildcard(&argc, &argv);
75 #endif
76
77         progname = *argv++;
78         argc--;
79
80         secure = 0;
81         s = lgetenv("LESSSECURE");
82         if (s != NULL && *s != '\0')
83                 secure = 1;
84
85 #ifdef WIN32
86         if (getenv("HOME") == NULL)
87         {
88                 /*
89                  * If there is no HOME environment variable,
90                  * try the concatenation of HOMEDRIVE + HOMEPATH.
91                  */
92                 char *drive = getenv("HOMEDRIVE");
93                 char *path  = getenv("HOMEPATH");
94                 if (drive != NULL && path != NULL)
95                 {
96                         char *env = (char *) ecalloc(strlen(drive) + 
97                                         strlen(path) + 6, sizeof(char));
98                         strcpy(env, "HOME=");
99                         strcat(env, drive);
100                         strcat(env, path);
101                         putenv(env);
102                 }
103         }
104         GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char));
105 #endif /* WIN32 */
106
107         /*
108          * Process command line arguments and LESS environment arguments.
109          * Command line arguments override environment arguments.
110          */
111         is_tty = isatty(1);
112         get_term();
113         init_cmds();
114         init_prompt();
115         init_charset();
116         init_line();
117         init_option();
118         s = lgetenv("LESS");
119         if (s != NULL)
120                 scan_option(save(s));
121
122 #define isoptstring(s)  (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
123         while (argc > 0 && (isoptstring(*argv) || isoptpending()))
124         {
125                 s = *argv++;
126                 argc--;
127                 if (strcmp(s, "--") == 0)
128                         break;
129                 scan_option(s);
130         }
131 #undef isoptstring
132
133         if (isoptpending())
134         {
135                 /*
136                  * Last command line option was a flag requiring a
137                  * following string, but there was no following string.
138                  */
139                 nopendopt();
140                 quit(QUIT_OK);
141         }
142
143 #if EDITOR
144         editor = lgetenv("VISUAL");
145         if (editor == NULL || *editor == '\0')
146         {
147                 editor = lgetenv("EDITOR");
148                 if (editor == NULL || *editor == '\0')
149                         editor = EDIT_PGM;
150         }
151         editproto = lgetenv("LESSEDIT");
152         if (editproto == NULL || *editproto == '\0')
153                 editproto = "%E ?lm+%lm. %f";
154 #endif
155
156         /*
157          * Call get_ifile with all the command line filenames
158          * to "register" them with the ifile system.
159          */
160         ifile = NULL_IFILE;
161         if (dohelp)
162                 ifile = get_ifile(FAKE_HELPFILE, ifile);
163         while (argc-- > 0)
164         {
165                 char *filename;
166 #if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
167                 /*
168                  * Because the "shell" doesn't expand filename patterns,
169                  * treat each argument as a filename pattern rather than
170                  * a single filename.  
171                  * Expand the pattern and iterate over the expanded list.
172                  */
173                 struct textlist tlist;
174                 char *gfilename;
175                 
176                 gfilename = lglob(*argv++);
177                 init_textlist(&tlist, gfilename);
178                 filename = NULL;
179                 while ((filename = forw_textlist(&tlist, filename)) != NULL)
180                 {
181                         (void) get_ifile(filename, ifile);
182                         ifile = prev_ifile(NULL_IFILE);
183                 }
184                 free(gfilename);
185 #else
186                 filename = shell_quote(*argv);
187                 if (filename == NULL)
188                         filename = *argv;
189                 argv++;
190                 (void) get_ifile(filename, ifile);
191                 ifile = prev_ifile(NULL_IFILE);
192 #endif
193         }
194         /*
195          * Set up terminal, etc.
196          */
197         if (!is_tty)
198         {
199                 /*
200                  * Output is not a tty.
201                  * Just copy the input file(s) to output.
202                  */
203                 SET_BINARY(1);
204                 if (nifile() == 0)
205                 {
206                         if (edit_stdin() == 0)
207                                 cat_file();
208                 } else if (edit_first() == 0)
209                 {
210                         do {
211                                 cat_file();
212                         } while (edit_next(1) == 0);
213                 }
214                 quit(QUIT_OK);
215         }
216
217         if (missing_cap && !know_dumb)
218                 error("WARNING: terminal is not fully functional", NULL_PARG);
219         init_mark();
220         open_getchr();
221         raw_mode(1);
222         init_signals(1);
223
224         /*
225          * Select the first file to examine.
226          */
227 #if TAGS
228         if (tagoption != NULL || strcmp(tags, "-") == 0)
229         {
230                 /*
231                  * A -t option was given.
232                  * Verify that no filenames were also given.
233                  * Edit the file selected by the "tags" search,
234                  * and search for the proper line in the file.
235                  */
236                 if (nifile() > 0)
237                 {
238                         error("No filenames allowed with -t option", NULL_PARG);
239                         quit(QUIT_ERROR);
240                 }
241                 findtag(tagoption);
242                 if (edit_tagfile())  /* Edit file which contains the tag */
243                         quit(QUIT_ERROR);
244                 /*
245                  * Search for the line which contains the tag.
246                  * Set up initial_scrpos so we display that line.
247                  */
248                 initial_scrpos.pos = tagsearch();
249                 if (initial_scrpos.pos == NULL_POSITION)
250                         quit(QUIT_ERROR);
251                 initial_scrpos.ln = jump_sline;
252         } else
253 #endif
254         if (nifile() == 0)
255         {
256                 if (edit_stdin())  /* Edit standard input */
257                         quit(QUIT_ERROR);
258         } else 
259         {
260                 if (edit_first())  /* Edit first valid file in cmd line */
261                         quit(QUIT_ERROR);
262         }
263
264         init();
265         commands();
266         quit(QUIT_OK);
267         /*NOTREACHED*/
268         return (0);
269 }
270
271 /*
272  * Copy a string to a "safe" place
273  * (that is, to a buffer allocated by calloc).
274  */
275         public char *
276 save(s)
277         char *s;
278 {
279         register char *p;
280
281         p = (char *) ecalloc(strlen(s)+1, sizeof(char));
282         strcpy(p, s);
283         return (p);
284 }
285
286 /*
287  * Allocate memory.
288  * Like calloc(), but never returns an error (NULL).
289  */
290         public VOID_POINTER
291 ecalloc(count, size)
292         int count;
293         unsigned int size;
294 {
295         register VOID_POINTER p;
296
297         p = (VOID_POINTER) calloc(count, size);
298         if (p != NULL)
299                 return (p);
300         error("Cannot allocate memory", NULL_PARG);
301         quit(QUIT_ERROR);
302         /*NOTREACHED*/
303         return (NULL);
304 }
305
306 /*
307  * Skip leading spaces in a string.
308  */
309         public char *
310 skipsp(s)
311         register char *s;
312 {
313         while (*s == ' ' || *s == '\t') 
314                 s++;
315         return (s);
316 }
317
318 /*
319  * See how many characters of two strings are identical.
320  * If uppercase is true, the first string must begin with an uppercase
321  * character; the remainder of the first string may be either case.
322  */
323         public int
324 sprefix(ps, s, uppercase)
325         char *ps;
326         char *s;
327         int uppercase;
328 {
329         register int c;
330         register int sc;
331         register int len = 0;
332
333         for ( ;  *s != '\0';  s++, ps++)
334         {
335                 c = *ps;
336                 if (uppercase)
337                 {
338                         if (len == 0 && SIMPLE_IS_LOWER(c))
339                                 return (-1);
340                         if (SIMPLE_IS_UPPER(c))
341                                 c = SIMPLE_TO_LOWER(c);
342                 }
343                 sc = *s;
344                 if (len > 0 && SIMPLE_IS_UPPER(sc))
345                         sc = SIMPLE_TO_LOWER(sc);
346                 if (c != sc)
347                         break;
348                 len++;
349         }
350         return (len);
351 }
352
353 /*
354  * Exit the program.
355  */
356         public void
357 quit(status)
358         int status;
359 {
360         static int save_status;
361
362         /*
363          * Put cursor at bottom left corner, clear the line,
364          * reset the terminal modes, and exit.
365          */
366         if (status < 0)
367                 status = save_status;
368         else
369                 save_status = status;
370         quitting = 1;
371         edit((char*)NULL);
372         if (any_display && is_tty)
373                 clear_bot();
374         deinit();
375         flush();
376         raw_mode(0);
377 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
378         /* 
379          * If we don't close 2, we get some garbage from
380          * 2's buffer when it flushes automatically.
381          * I cannot track this one down  RB
382          * The same bug shows up if we use ^C^C to abort.
383          */
384         close(2);
385 #endif
386 #if WIN32
387         SetConsoleTitle(consoleTitle);
388 #endif
389         close_getchr();
390         exit(status);
391 }