2 * Copyright (C) 1984-2022 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 int want_filesize;
30 extern int consecutive_nulls;
31 extern IFILE curr_ifile;
32 extern IFILE old_ifile;
33 extern struct scrpos initial_scrpos;
34 extern void *ml_examine;
35 #if SPACES_IN_FILENAMES
36 extern char openquote;
37 extern char closequote;
42 extern int force_logfile;
43 extern char *namelogfile;
47 public dev_t curr_dev;
48 public ino_t curr_ino;
52 * Textlist functions deal with a list of words separated by spaces.
53 * init_textlist sets up a textlist structure.
54 * forw_textlist uses that structure to iterate thru the list of
55 * words, returning each one as a standard null-terminated string.
56 * back_textlist does the same, but runs thru the list backwards.
59 init_textlist(tlist, str)
60 struct textlist *tlist;
64 #if SPACES_IN_FILENAMES
67 char *esc = get_meta_escape();
68 int esclen = (int) strlen(esc);
71 tlist->string = skipsp(str);
72 tlist->endstring = tlist->string + strlen(tlist->string);
73 for (s = str; s < tlist->endstring; s++)
75 #if SPACES_IN_FILENAMES
79 } else if (esclen > 0 && s + esclen < tlist->endstring &&
80 strncmp(s, esc, esclen) == 0)
84 } else if (delim_quoted)
88 } else /* (!delim_quoted) */
103 forw_textlist(tlist, prev)
104 struct textlist *tlist;
110 * prev == NULL means return the first word in the list.
111 * Otherwise, return the word after "prev".
116 s = prev + strlen(prev);
117 if (s >= tlist->endstring)
121 if (s >= tlist->endstring)
127 back_textlist(tlist, prev)
128 struct textlist *tlist;
134 * prev == NULL means return the last word in the list.
135 * Otherwise, return the word before "prev".
138 s = tlist->endstring;
139 else if (prev <= tlist->string)
145 if (s <= tlist->string)
147 while (s[-1] != '\0' && s > tlist->string)
153 * Close a pipe opened via popen.
156 close_pipe(FILE *pipefd)
162 * The pclose function of OS/2 emx sometimes fails.
163 * Send SIGINT to the piped process before closing it.
165 kill(pipefd->_pid, SIGINT);
171 * Close the current input file.
174 close_file(VOID_PARAM)
176 struct scrpos scrpos;
181 if (curr_ifile == NULL_IFILE)
185 * Save the current position so that we can return to
186 * the same position if we edit this file again.
188 get_scrpos(&scrpos, TOP);
189 if (scrpos.pos != NULL_POSITION)
191 store_pos(curr_ifile, &scrpos);
195 * Close the file descriptor, unless it is a pipe.
197 chflags = ch_getflags();
200 * If we opened a file using an alternate name,
201 * do special stuff to close it.
203 altfilename = get_altfilename(curr_ifile);
204 if (altfilename != NULL)
206 altpipe = get_altpipe(curr_ifile);
207 if (altpipe != NULL && !(chflags & CH_KEEPOPEN))
210 set_altpipe(curr_ifile, NULL);
212 close_altfile(altfilename, get_filename(curr_ifile));
213 set_altfilename(curr_ifile, NULL);
215 curr_ifile = NULL_IFILE;
217 curr_ino = curr_dev = 0;
222 * Edit a new file (given its name).
223 * Filename == "-" means standard input.
224 * Filename == NULL means just close the current file.
230 if (filename == NULL)
231 return (edit_ifile(NULL_IFILE));
232 return (edit_ifile(get_ifile(filename, curr_ifile)));
236 * Edit a new file (given its IFILE).
237 * ifile == NULL means just close the current file.
250 IFILE was_curr_ifile;
253 if (ifile == curr_ifile)
256 * Already have the correct file open.
262 * We must close the currently open file now.
263 * This is necessary to make the open_altfile/close_altfile pairs
264 * nest properly (or rather to avoid nesting at all).
265 * {{ Some stupid implementations of popen() mess up if you do:
266 * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
271 was_curr_ifile = save_curr_ifile();
272 if (curr_ifile != NULL_IFILE)
274 chflags = ch_getflags();
276 if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
279 * Don't keep the help file in the ifile list.
281 del_ifile(was_curr_ifile);
282 was_curr_ifile = old_ifile;
286 if (ifile == NULL_IFILE)
289 * No new file to open.
290 * (Don't set old_ifile, because if you call edit_ifile(NULL),
291 * you're supposed to have saved curr_ifile yourself,
292 * and you'll restore it if necessary.)
294 unsave_ifile(was_curr_ifile);
298 filename = save(get_filename(ifile));
301 * See if LESSOPEN specifies an "alternate" file to open.
303 altpipe = get_altpipe(ifile);
307 * File is already open.
308 * chflags and f are not used by ch_init if ifile has
309 * filestate which should be the case if we're here.
310 * Set them here to avoid uninitialized variable warnings.
314 alt_filename = get_altfilename(ifile);
315 open_filename = (alt_filename != NULL) ? alt_filename : filename;
318 if (strcmp(filename, FAKE_HELPFILE) == 0 ||
319 strcmp(filename, FAKE_EMPTYFILE) == 0)
322 alt_filename = open_altfile(filename, &f, &altpipe);
324 open_filename = (alt_filename != NULL) ? alt_filename : filename;
330 * The alternate "file" is actually a pipe.
331 * f has already been set to the file descriptor of the pipe
332 * in the call to open_altfile above.
333 * Keep the file descriptor open because it was opened
334 * via popen(), and pclose() wants to close it.
336 chflags |= CH_POPENED;
337 if (strcmp(filename, "-") == 0)
338 chflags |= CH_KEEPOPEN;
339 } else if (strcmp(filename, "-") == 0)
342 * Use standard input.
343 * Keep the file descriptor open because we can't reopen it.
346 chflags |= CH_KEEPOPEN;
348 * Must switch stdin to BINARY mode.
351 #if MSDOS_COMPILER==DJGPPC
353 * Setting stdin to binary by default causes
354 * Ctrl-C to not raise SIGINT. We must undo
357 __djgpp_set_ctrl_c(1);
359 } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
362 chflags |= CH_NODATA;
363 } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
366 chflags |= CH_HELPFILE;
367 } else if ((parg.p_string = bad_file(open_filename)) != NULL)
370 * It looks like a bad file. Don't try to open it.
375 if (alt_filename != NULL)
378 close_altfile(alt_filename, filename);
384 * Re-open the current file.
386 if (was_curr_ifile == ifile)
389 * Whoops. The "current" ifile is the one we just deleted.
394 reedit_ifile(was_curr_ifile);
396 } else if ((f = open(open_filename, OPEN_READ)) < 0)
399 * Got an error trying to open it.
401 parg.p_string = errno_message(filename);
407 chflags |= CH_CANSEEK;
408 if (!force_open && !opened(ifile) && bin_file(f))
411 * Looks like a binary file.
412 * Ask user if we should proceed.
414 parg.p_string = filename;
415 answer = query("\"%s\" may be a binary file. See it anyway? ",
417 if (answer != 'y' && answer != 'Y')
428 * Get the saved position for the file.
430 if (was_curr_ifile != NULL_IFILE)
432 old_ifile = was_curr_ifile;
433 unsave_ifile(was_curr_ifile);
436 set_altfilename(curr_ifile, alt_filename);
437 set_altpipe(curr_ifile, altpipe);
438 set_open(curr_ifile); /* File has been opened */
439 get_pos(curr_ifile, &initial_scrpos);
442 consecutive_nulls = 0;
444 if (!(chflags & CH_HELPFILE))
447 if (namelogfile != NULL && is_tty)
448 use_logfile(namelogfile);
451 /* Remember the i-number and device of the opened file. */
452 if (strcmp(open_filename, "-") != 0)
455 int r = stat(open_filename, &statbuf);
458 curr_ino = statbuf.st_ino;
459 curr_dev = statbuf.st_dev;
463 if (every_first_cmd != NULL)
465 ungetsc(every_first_cmd);
466 ungetcc_back(CHAR_END_COMMAND);
475 * Output is to a real tty.
479 * Indicate there is nothing displayed yet.
487 if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE))
489 char *qfilename = shell_quote(filename);
490 cmd_addhist(ml_examine, qfilename, 1);
501 * Edit a space-separated list of files.
502 * For each filename in the list, enter it into the ifile list.
503 * Then edit the first one.
515 struct textlist tl_files;
516 struct textlist tl_gfiles;
518 save_ifile = save_curr_ifile();
519 good_filename = NULL;
522 * Run thru each filename in the list.
523 * Try to glob the filename.
524 * If it doesn't expand, just try to open the filename.
525 * If it does expand, try to open each name in that list.
527 init_textlist(&tl_files, filelist);
529 while ((filename = forw_textlist(&tl_files, filename)) != NULL)
531 gfilelist = lglob(filename);
532 init_textlist(&tl_gfiles, gfilelist);
534 while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
536 qfilename = shell_unquote(gfilename);
537 if (edit(qfilename) == 0 && good_filename == NULL)
538 good_filename = get_filename(curr_ifile);
544 * Edit the first valid filename in the list.
546 if (good_filename == NULL)
548 unsave_ifile(save_ifile);
551 if (get_ifile(good_filename, curr_ifile) == curr_ifile)
554 * Trying to edit the current file; don't reopen it.
556 unsave_ifile(save_ifile);
559 reedit_ifile(save_ifile);
560 return (edit(good_filename));
564 * Edit the first file in the command line (ifile) list.
567 edit_first(VOID_PARAM)
570 return (edit_stdin());
571 curr_ifile = NULL_IFILE;
572 return (edit_next(1));
576 * Edit the last file in the command line (ifile) list.
579 edit_last(VOID_PARAM)
581 curr_ifile = NULL_IFILE;
582 return (edit_prev(1));
587 * Edit the n-th next or previous file in the command line (ifile) list.
590 edit_istep(h, n, dir)
598 * Skip n filenames, then try to edit each filename.
602 next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
605 if (edit_ifile(h) == 0)
608 if (next == NULL_IFILE)
611 * Reached end of the ifile list.
618 * Interrupt breaks out, if we're in a long
619 * list of files that can't be opened.
626 * Found a file that we can edit.
636 return (edit_istep(h, n, +1));
643 return edit_istep(curr_ifile, n, +1);
651 return (edit_istep(h, n, -1));
658 return edit_istep(curr_ifile, n, -1);
662 * Edit a specific file in the command line (ifile) list.
673 if ((h = next_ifile(h)) == NULL_IFILE)
676 * Reached end of the list without finding it.
680 } while (get_index(h) != n);
682 return (edit_ifile(h));
686 save_curr_ifile(VOID_PARAM)
688 if (curr_ifile != NULL_IFILE)
689 hold_ifile(curr_ifile, 1);
694 unsave_ifile(save_ifile)
697 if (save_ifile != NULL_IFILE)
698 hold_ifile(save_ifile, -1);
702 * Reedit the ifile which was previously open.
705 reedit_ifile(save_ifile)
712 * Try to reopen the ifile.
713 * Note that opening it may fail (maybe the file was removed),
714 * in which case the ifile will be deleted from the list.
715 * So save the next and prev ifiles first.
717 unsave_ifile(save_ifile);
718 next = next_ifile(save_ifile);
719 prev = prev_ifile(save_ifile);
720 if (edit_ifile(save_ifile) == 0)
723 * If can't reopen it, open the next input file in the list.
725 if (next != NULL_IFILE && edit_inext(next, 0) == 0)
728 * If can't open THAT one, open the previous input file in the list.
730 if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
733 * If can't even open that, we're stuck. Just quit.
739 reopen_curr_ifile(VOID_PARAM)
741 IFILE save_ifile = save_curr_ifile();
743 reedit_ifile(save_ifile);
747 * Edit standard input.
750 edit_stdin(VOID_PARAM)
754 error("Missing filename (\"less --help\" for help)", NULL_PARG);
761 * Copy a file directly to standard output.
762 * Used if standard output is not a tty.
769 while ((c = ch_forw_get()) != EOI)
776 #define OVERWRITE_OPTIONS "Overwrite, Append, Don't log, or Quit?"
779 * If the user asked for a log file and our input file
780 * is standard input, create the log file.
781 * We take care not to blindly overwrite an existing file.
784 use_logfile(filename)
791 if (ch_getflags() & CH_CANSEEK)
793 * Can't currently use a log file on a file that can seek.
798 * {{ We could use access() here. }}
800 exists = open(filename, OPEN_READ);
803 exists = (exists >= 0);
806 * Decide whether to overwrite the log file or append to it.
807 * If it doesn't exist we "overwrite" it.
809 if (!exists || force_logfile)
812 * Overwrite (or create) the log file.
818 * Ask user what to do.
820 parg.p_string = filename;
821 answer = query("Warning: \"%s\" exists; "OVERWRITE_OPTIONS" ", &parg);
829 * Overwrite: create the file.
831 logfile = creat(filename, 0644);
835 * Append: open the file and seek to the end.
837 logfile = open(filename, OPEN_APPEND);
838 if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK)
854 answer = query(OVERWRITE_OPTIONS" (Type \"O\", \"A\", \"D\" or \"Q\") ", NULL_PARG);
861 * Error in opening logfile.
863 parg.p_string = filename;
864 error("Cannot write to \"%s\"", &parg);