2 * Copyright (C) 1984-2021 Mark Nudelman
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.
7 * For more information, see the README file.
24 extern char *every_first_cmd;
25 extern int force_open;
29 extern IFILE curr_ifile;
30 extern IFILE old_ifile;
31 extern struct scrpos initial_scrpos;
32 extern void *ml_examine;
33 #if SPACES_IN_FILENAMES
34 extern char openquote;
35 extern char closequote;
40 extern int force_logfile;
41 extern char *namelogfile;
45 public dev_t curr_dev;
46 public ino_t curr_ino;
50 * Textlist functions deal with a list of words separated by spaces.
51 * init_textlist sets up a textlist structure.
52 * forw_textlist uses that structure to iterate thru the list of
53 * words, returning each one as a standard null-terminated string.
54 * back_textlist does the same, but runs thru the list backwards.
57 init_textlist(tlist, str)
58 struct textlist *tlist;
62 #if SPACES_IN_FILENAMES
65 char *esc = get_meta_escape();
66 int esclen = (int) strlen(esc);
69 tlist->string = skipsp(str);
70 tlist->endstring = tlist->string + strlen(tlist->string);
71 for (s = str; s < tlist->endstring; s++)
73 #if SPACES_IN_FILENAMES
77 } else if (esclen > 0 && s + esclen < tlist->endstring &&
78 strncmp(s, esc, esclen) == 0)
82 } else if (delim_quoted)
86 } else /* (!delim_quoted) */
101 forw_textlist(tlist, prev)
102 struct textlist *tlist;
108 * prev == NULL means return the first word in the list.
109 * Otherwise, return the word after "prev".
114 s = prev + strlen(prev);
115 if (s >= tlist->endstring)
119 if (s >= tlist->endstring)
125 back_textlist(tlist, prev)
126 struct textlist *tlist;
132 * prev == NULL means return the last word in the list.
133 * Otherwise, return the word before "prev".
136 s = tlist->endstring;
137 else if (prev <= tlist->string)
143 if (s <= tlist->string)
145 while (s[-1] != '\0' && s > tlist->string)
151 * Close a pipe opened via popen.
154 close_pipe(FILE *pipefd)
160 * The pclose function of OS/2 emx sometimes fails.
161 * Send SIGINT to the piped process before closing it.
163 kill(pipefd->_pid, SIGINT);
169 * Close the current input file.
172 close_file(VOID_PARAM)
174 struct scrpos scrpos;
179 if (curr_ifile == NULL_IFILE)
183 * Save the current position so that we can return to
184 * the same position if we edit this file again.
186 get_scrpos(&scrpos, TOP);
187 if (scrpos.pos != NULL_POSITION)
189 store_pos(curr_ifile, &scrpos);
193 * Close the file descriptor, unless it is a pipe.
195 chflags = ch_getflags();
198 * If we opened a file using an alternate name,
199 * do special stuff to close it.
201 altfilename = get_altfilename(curr_ifile);
202 if (altfilename != NULL)
204 altpipe = get_altpipe(curr_ifile);
205 if (altpipe != NULL && !(chflags & CH_KEEPOPEN))
208 set_altpipe(curr_ifile, NULL);
210 close_altfile(altfilename, get_filename(curr_ifile));
211 set_altfilename(curr_ifile, NULL);
213 curr_ifile = NULL_IFILE;
215 curr_ino = curr_dev = 0;
220 * Edit a new file (given its name).
221 * Filename == "-" means standard input.
222 * Filename == NULL means just close the current file.
228 if (filename == NULL)
229 return (edit_ifile(NULL_IFILE));
230 return (edit_ifile(get_ifile(filename, curr_ifile)));
234 * Edit a new file (given its IFILE).
235 * ifile == NULL means just close the current file.
248 IFILE was_curr_ifile;
251 if (ifile == curr_ifile)
254 * Already have the correct file open.
260 * We must close the currently open file now.
261 * This is necessary to make the open_altfile/close_altfile pairs
262 * nest properly (or rather to avoid nesting at all).
263 * {{ Some stupid implementations of popen() mess up if you do:
264 * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
269 was_curr_ifile = save_curr_ifile();
270 if (curr_ifile != NULL_IFILE)
272 chflags = ch_getflags();
274 if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
277 * Don't keep the help file in the ifile list.
279 del_ifile(was_curr_ifile);
280 was_curr_ifile = old_ifile;
284 if (ifile == NULL_IFILE)
287 * No new file to open.
288 * (Don't set old_ifile, because if you call edit_ifile(NULL),
289 * you're supposed to have saved curr_ifile yourself,
290 * and you'll restore it if necessary.)
292 unsave_ifile(was_curr_ifile);
296 filename = save(get_filename(ifile));
299 * See if LESSOPEN specifies an "alternate" file to open.
301 altpipe = get_altpipe(ifile);
305 * File is already open.
306 * chflags and f are not used by ch_init if ifile has
307 * filestate which should be the case if we're here.
308 * Set them here to avoid uninitialized variable warnings.
312 alt_filename = get_altfilename(ifile);
313 open_filename = (alt_filename != NULL) ? alt_filename : filename;
316 if (strcmp(filename, FAKE_HELPFILE) == 0 ||
317 strcmp(filename, FAKE_EMPTYFILE) == 0)
320 alt_filename = open_altfile(filename, &f, &altpipe);
322 open_filename = (alt_filename != NULL) ? alt_filename : filename;
328 * The alternate "file" is actually a pipe.
329 * f has already been set to the file descriptor of the pipe
330 * in the call to open_altfile above.
331 * Keep the file descriptor open because it was opened
332 * via popen(), and pclose() wants to close it.
334 chflags |= CH_POPENED;
335 if (strcmp(filename, "-") == 0)
336 chflags |= CH_KEEPOPEN;
337 } else if (strcmp(filename, "-") == 0)
340 * Use standard input.
341 * Keep the file descriptor open because we can't reopen it.
344 chflags |= CH_KEEPOPEN;
346 * Must switch stdin to BINARY mode.
349 #if MSDOS_COMPILER==DJGPPC
351 * Setting stdin to binary by default causes
352 * Ctrl-C to not raise SIGINT. We must undo
355 __djgpp_set_ctrl_c(1);
357 } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
360 chflags |= CH_NODATA;
361 } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
364 chflags |= CH_HELPFILE;
365 } else if ((parg.p_string = bad_file(open_filename)) != NULL)
368 * It looks like a bad file. Don't try to open it.
373 if (alt_filename != NULL)
376 close_altfile(alt_filename, filename);
382 * Re-open the current file.
384 if (was_curr_ifile == ifile)
387 * Whoops. The "current" ifile is the one we just deleted.
392 reedit_ifile(was_curr_ifile);
394 } else if ((f = open(open_filename, OPEN_READ)) < 0)
397 * Got an error trying to open it.
399 parg.p_string = errno_message(filename);
405 chflags |= CH_CANSEEK;
406 if (!force_open && !opened(ifile) && bin_file(f))
409 * Looks like a binary file.
410 * Ask user if we should proceed.
412 parg.p_string = filename;
413 answer = query("\"%s\" may be a binary file. See it anyway? ",
415 if (answer != 'y' && answer != 'Y')
426 * Get the saved position for the file.
428 if (was_curr_ifile != NULL_IFILE)
430 old_ifile = was_curr_ifile;
431 unsave_ifile(was_curr_ifile);
434 set_altfilename(curr_ifile, alt_filename);
435 set_altpipe(curr_ifile, altpipe);
436 set_open(curr_ifile); /* File has been opened */
437 get_pos(curr_ifile, &initial_scrpos);
441 if (!(chflags & CH_HELPFILE))
444 if (namelogfile != NULL && is_tty)
445 use_logfile(namelogfile);
448 /* Remember the i-number and device of the opened file. */
449 if (strcmp(open_filename, "-") != 0)
452 int r = stat(open_filename, &statbuf);
455 curr_ino = statbuf.st_ino;
456 curr_dev = statbuf.st_dev;
460 if (every_first_cmd != NULL)
462 ungetsc(every_first_cmd);
463 ungetcc_back(CHAR_END_COMMAND);
472 * Output is to a real tty.
476 * Indicate there is nothing displayed yet.
484 if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE))
486 char *qfilename = shell_quote(filename);
487 cmd_addhist(ml_examine, qfilename, 1);
497 * Edit a space-separated list of files.
498 * For each filename in the list, enter it into the ifile list.
499 * Then edit the first one.
511 struct textlist tl_files;
512 struct textlist tl_gfiles;
514 save_ifile = save_curr_ifile();
515 good_filename = NULL;
518 * Run thru each filename in the list.
519 * Try to glob the filename.
520 * If it doesn't expand, just try to open the filename.
521 * If it does expand, try to open each name in that list.
523 init_textlist(&tl_files, filelist);
525 while ((filename = forw_textlist(&tl_files, filename)) != NULL)
527 gfilelist = lglob(filename);
528 init_textlist(&tl_gfiles, gfilelist);
530 while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
532 qfilename = shell_unquote(gfilename);
533 if (edit(qfilename) == 0 && good_filename == NULL)
534 good_filename = get_filename(curr_ifile);
540 * Edit the first valid filename in the list.
542 if (good_filename == NULL)
544 unsave_ifile(save_ifile);
547 if (get_ifile(good_filename, curr_ifile) == curr_ifile)
550 * Trying to edit the current file; don't reopen it.
552 unsave_ifile(save_ifile);
555 reedit_ifile(save_ifile);
556 return (edit(good_filename));
560 * Edit the first file in the command line (ifile) list.
563 edit_first(VOID_PARAM)
566 return (edit_stdin());
567 curr_ifile = NULL_IFILE;
568 return (edit_next(1));
572 * Edit the last file in the command line (ifile) list.
575 edit_last(VOID_PARAM)
577 curr_ifile = NULL_IFILE;
578 return (edit_prev(1));
583 * Edit the n-th next or previous file in the command line (ifile) list.
586 edit_istep(h, n, dir)
594 * Skip n filenames, then try to edit each filename.
598 next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
601 if (edit_ifile(h) == 0)
604 if (next == NULL_IFILE)
607 * Reached end of the ifile list.
614 * Interrupt breaks out, if we're in a long
615 * list of files that can't be opened.
622 * Found a file that we can edit.
632 return (edit_istep(h, n, +1));
639 return edit_istep(curr_ifile, n, +1);
647 return (edit_istep(h, n, -1));
654 return edit_istep(curr_ifile, n, -1);
658 * Edit a specific file in the command line (ifile) list.
669 if ((h = next_ifile(h)) == NULL_IFILE)
672 * Reached end of the list without finding it.
676 } while (get_index(h) != n);
678 return (edit_ifile(h));
682 save_curr_ifile(VOID_PARAM)
684 if (curr_ifile != NULL_IFILE)
685 hold_ifile(curr_ifile, 1);
690 unsave_ifile(save_ifile)
693 if (save_ifile != NULL_IFILE)
694 hold_ifile(save_ifile, -1);
698 * Reedit the ifile which was previously open.
701 reedit_ifile(save_ifile)
708 * Try to reopen the ifile.
709 * Note that opening it may fail (maybe the file was removed),
710 * in which case the ifile will be deleted from the list.
711 * So save the next and prev ifiles first.
713 unsave_ifile(save_ifile);
714 next = next_ifile(save_ifile);
715 prev = prev_ifile(save_ifile);
716 if (edit_ifile(save_ifile) == 0)
719 * If can't reopen it, open the next input file in the list.
721 if (next != NULL_IFILE && edit_inext(next, 0) == 0)
724 * If can't open THAT one, open the previous input file in the list.
726 if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
729 * If can't even open that, we're stuck. Just quit.
735 reopen_curr_ifile(VOID_PARAM)
737 IFILE save_ifile = save_curr_ifile();
739 reedit_ifile(save_ifile);
743 * Edit standard input.
746 edit_stdin(VOID_PARAM)
750 error("Missing filename (\"less --help\" for help)", NULL_PARG);
757 * Copy a file directly to standard output.
758 * Used if standard output is not a tty.
765 while ((c = ch_forw_get()) != EOI)
772 #define OVERWRITE_OPTIONS "Overwrite, Append, Don't log, or Quit?"
775 * If the user asked for a log file and our input file
776 * is standard input, create the log file.
777 * We take care not to blindly overwrite an existing file.
780 use_logfile(filename)
787 if (ch_getflags() & CH_CANSEEK)
789 * Can't currently use a log file on a file that can seek.
794 * {{ We could use access() here. }}
796 exists = open(filename, OPEN_READ);
799 exists = (exists >= 0);
802 * Decide whether to overwrite the log file or append to it.
803 * If it doesn't exist we "overwrite" it.
805 if (!exists || force_logfile)
808 * Overwrite (or create) the log file.
814 * Ask user what to do.
816 parg.p_string = filename;
817 answer = query("Warning: \"%s\" exists; "OVERWRITE_OPTIONS" ", &parg);
825 * Overwrite: create the file.
827 logfile = creat(filename, 0644);
831 * Append: open the file and seek to the end.
833 logfile = open(filename, OPEN_APPEND);
834 if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK)
850 answer = query(OVERWRITE_OPTIONS" (Type \"O\", \"A\", \"D\" or \"Q\") ", NULL_PARG);
857 * Error in opening logfile.
859 parg.p_string = filename;
860 error("Cannot write to \"%s\"", &parg);