1 /*
2 * Entry point, initialization, miscellaneous routines.
3 */
4
5 #include "less.h"
6 #include "position.h"
7
8 public int ispipe;
9 public char * first_cmd;
10 public char * every_first_cmd;
11 public int new_file;
12 public int is_tty;
13 public char *current_file;
14 public char *previous_file;
15 public POSITION prev_pos;
16 public int any_display;
17 public int scroll;
18 public int ac;
19 public char ** av;
20 public int curr_ac;
21 public int quitting;
22
23 extern int file;
24 extern int quit_at_eof;
25 extern int cbufs;
26 extern int errmsgs;
27
28 #if LOGFILE
29 public int logfile = -1;
30 public int force_logfile = 0;
31 public char * namelogfile = NULL;
32 #endif
33
34 #if EDITOR
35 public char * editor;
36 #endif
37
38 #if TAGS
39 extern char * tagfile;
40 extern char * tagpattern;
41 extern int tagoption;
42 #endif
43
44
45 /*
46 * Edit a new file.
47 * Filename "-" means standard input.
48 * No filename means the "current" file, from the command line.
49 */
50 public void
edit(filename)51 edit(filename)
52 register char *filename;
53 {
54 register int f;
55 register char *m;
56 POSITION initial_pos;
57 char message[100];
58 static int didpipe;
59
60 initial_pos = NULL_POSITION;
61 if (filename == NULL || *filename == '\0')
62 {
63 if (curr_ac >= ac)
64 {
65 error("No current file");
66 return;
67 }
68 filename = save(av[curr_ac]);
69 } else if (strcmp(filename, "#") == 0)
70 {
71 if (*previous_file == '\0')
72 {
73 error("no previous file");
74 return;
75 }
76 filename = save(previous_file);
77 initial_pos = prev_pos;
78 } else
79 filename = save(filename);
80
81 if (strcmp(filename, "-") == 0)
82 {
83 /*
84 * Use standard input.
85 */
86 if (didpipe)
87 {
88 error("Can view standard input only once");
89 return;
90 }
91 f = 0;
92 } else if ((m = bad_file(filename, message, sizeof(message))) != NULL)
93 {
94 error(m);
95 free(filename);
96 return;
97 } else if ((f = open(filename, 0)) < 0)
98 {
99 error(errno_message(filename, message, sizeof(message)));
100 free(filename);
101 return;
102 }
103
104 if (isatty(f))
105 {
106 /*
107 * Not really necessary to call this an error,
108 * but if the control terminal (for commands)
109 * and the input file (for data) are the same,
110 * we get weird results at best.
111 */
112 error("Can't take input from a terminal");
113 if (f > 0)
114 close(f);
115 free(filename);
116 return;
117 }
118
119 #if LOGFILE
120 if (f == 0 && namelogfile != NULL && is_tty)
121 use_logfile();
122 #endif
123
124 /*
125 * We are now committed to using the new file.
126 * Close the current input file and set up to use the new one.
127 */
128 if (file > 0)
129 close(file);
130 new_file = 1;
131 if (previous_file != NULL)
132 free(previous_file);
133 previous_file = current_file;
134 current_file = filename;
135 prev_pos = position(TOP);
136 ispipe = (f == 0);
137 if (ispipe)
138 didpipe = 1;
139 file = f;
140 ch_init(cbufs, 0);
141 init_mark();
142
143 if (every_first_cmd != NULL)
144 first_cmd = every_first_cmd;
145
146 if (is_tty)
147 {
148 int no_display = !any_display;
149 any_display = 1;
150 if (no_display && errmsgs > 0)
151 {
152 /*
153 * We displayed some messages on error output
154 * (file descriptor 2; see error() function).
155 * Before erasing the screen contents,
156 * display the file name and wait for a keystroke.
157 */
158 error(filename);
159 }
160 /*
161 * Indicate there is nothing displayed yet.
162 */
163 pos_clear();
164 if (initial_pos != NULL_POSITION)
165 jump_loc(initial_pos);
166 clr_linenum();
167 }
168 }
169
170 /*
171 * Edit the next file in the command line list.
172 */
173 public void
next_file(n)174 next_file(n)
175 int n;
176 {
177 if (curr_ac + n >= ac)
178 {
179 if (quit_at_eof)
180 quit();
181 error("No (N-th) next file");
182 } else
183 edit(av[curr_ac += n]);
184 }
185
186 /*
187 * Edit the previous file in the command line list.
188 */
189 public void
prev_file(n)190 prev_file(n)
191 int n;
192 {
193 if (curr_ac - n < 0)
194 error("No (N-th) previous file");
195 else
196 edit(av[curr_ac -= n]);
197 }
198
199 /*
200 * Copy a file directly to standard output.
201 * Used if standard output is not a tty.
202 */
203 static void
cat_file()204 cat_file()
205 {
206 register int c;
207
208 while ((c = ch_forw_get()) != EOI)
209 putchr(c);
210 flush();
211 }
212
213 #if LOGFILE
214
use_logfile()215 use_logfile()
216 {
217 int exists;
218 int answer;
219 char message[100];
220
221 /*
222 * If he asked for a log file and we have opened standard input,
223 * create the log file.
224 * We take care not to blindly overwrite an existing file.
225 */
226 end_logfile();
227
228 /*
229 * {{ We could use access() here. }}
230 */
231 exists = open(namelogfile, 0);
232 close(exists);
233 exists = (exists >= 0);
234
235 if (exists && !force_logfile)
236 {
237 static char w[] = "WARNING: log file exists: ";
238 strcpy(message, w);
239 strtcpy(message+sizeof(w)-1, namelogfile,
240 sizeof(message)-sizeof(w));
241 error(message);
242 answer = 'X'; /* Ask the user what to do */
243 } else
244 answer = 'O'; /* Create the log file */
245
246 loop:
247 switch (answer)
248 {
249 case 'O': case 'o':
250 logfile = creat(namelogfile, 0644);
251 break;
252 case 'A': case 'a':
253 logfile = open(namelogfile, 1);
254 if (lseek(logfile, (offset_t)0, 2) < 0)
255 {
256 close(logfile);
257 logfile = -1;
258 }
259 break;
260 case 'D': case 'd':
261 answer = 0; /* Don't print an error message */
262 break;
263 case 'q':
264 quit();
265 default:
266 putstr("\n Overwrite, Append, or Don't log? ");
267 answer = getchr();
268 putstr("\n");
269 flush();
270 goto loop;
271 }
272
273 if (logfile < 0 && answer != 0)
274 {
275 sprintf(message, "Cannot write to \"%s\"",
276 namelogfile);
277 error(message);
278 }
279 }
280
281 #endif
282
283 /*
284 * Entry point.
285 */
main(argc,argv)286 main(argc, argv)
287 int argc;
288 char *argv[];
289 {
290 char *getenv();
291
292
293 /*
294 * Process command line arguments and LESS environment arguments.
295 * Command line arguments override environment arguments.
296 */
297 init_prompt();
298 init_option();
299 scan_option(getenv("LESS"));
300 argv++;
301 while ( (--argc > 0) &&
302 (argv[0][0] == '-' || argv[0][0] == '+') &&
303 argv[0][1] != '\0')
304 scan_option(*argv++);
305
306 #if EDITOR
307 editor = getenv("EDITOR");
308 if (editor == NULL || *editor == '\0')
309 editor = EDIT_PGM;
310 #endif
311
312 /*
313 * Set up list of files to be examined.
314 */
315 ac = argc;
316 av = argv;
317 curr_ac = 0;
318
319 /*
320 * Set up terminal, etc.
321 */
322 is_tty = isatty(1);
323 if (!is_tty)
324 {
325 /*
326 * Output is not a tty.
327 * Just copy the input file(s) to output.
328 */
329 if (ac < 1)
330 {
331 edit("-");
332 cat_file();
333 } else
334 {
335 do
336 {
337 edit((char *)NULL);
338 if (file >= 0)
339 cat_file();
340 } while (++curr_ac < ac);
341 }
342 exit(0);
343 }
344
345 raw_mode(1);
346 get_term();
347 open_getchr();
348 init();
349 init_cmd();
350
351 init_signals(1);
352
353 /*
354 * Select the first file to examine.
355 */
356 #if TAGS
357 if (tagoption)
358 {
359 /*
360 * A -t option was given.
361 * Verify that no filenames were also given.
362 * Edit the file selected by the "tags" search,
363 * and search for the proper line in the file.
364 */
365 if (ac > 0)
366 {
367 error("No filenames allowed with -t option");
368 quit();
369 }
370 if (tagfile == NULL)
371 quit();
372 edit(tagfile);
373 if (file < 0)
374 quit();
375 if (tagsearch())
376 quit();
377 } else
378 #endif
379 if (ac < 1)
380 edit("-"); /* Standard input */
381 else
382 {
383 /*
384 * Try all the files named as command arguments.
385 * We are simply looking for one which can be
386 * opened without error.
387 */
388 do
389 {
390 edit((char *)NULL);
391 } while (file < 0 && ++curr_ac < ac);
392 }
393
394 if (file >= 0)
395 commands();
396 quit();
397 /*NOTREACHED*/
398 }
399
400 /*
401 * Copy a string, truncating to the specified length if necessary.
402 * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
403 */
404 public void
strtcpy(to,from,len)405 strtcpy(to, from, len)
406 char *to;
407 char *from;
408 unsigned int len;
409 {
410 strncpy(to, from, len);
411 to[len-1] = '\0';
412 }
413
414 /*
415 * Copy a string to a "safe" place
416 * (that is, to a buffer allocated by calloc).
417 */
418 public char *
save(s)419 save(s)
420 char *s;
421 {
422 register char *p;
423
424 p = calloc(strlen(s)+1, sizeof(char));
425 if (p == NULL)
426 {
427 error("cannot allocate memory");
428 quit();
429 }
430 strcpy(p, s);
431 return (p);
432 }
433
434 /*
435 * Exit the program.
436 */
437 public void
quit()438 quit()
439 {
440 /*
441 * Put cursor at bottom left corner, clear the line,
442 * reset the terminal modes, and exit.
443 */
444 quitting = 1;
445 #if LOGFILE
446 end_logfile();
447 #endif
448 lower_left();
449 clear_eol();
450 deinit();
451 flush();
452 raw_mode(0);
453 exit(0);
454 }
455