1 /* $NetBSD: edit.c,v 1.4 2013/09/04 19:44:21 tron Exp $ */
4 * Copyright (C) 1984-2012 Mark Nudelman
6 * You may distribute under the terms of either the GNU General Public
7 * License or the Less License, as specified in the README file.
9 * For more information, see the README file.
23 extern char *every_first_cmd
;
24 extern int any_display
;
25 extern int force_open
;
28 extern IFILE curr_ifile
;
29 extern IFILE old_ifile
;
30 extern struct scrpos initial_scrpos
;
31 extern void *constant ml_examine
;
32 #if SPACES_IN_FILENAMES
33 extern char openquote
;
34 extern char closequote
;
39 extern int force_logfile
;
40 extern char *namelogfile
;
44 public dev_t curr_dev
;
45 public ino_t curr_ino
;
48 char *curr_altfilename
= NULL
;
49 static void *curr_altpipe
;
52 static void close_file
__P((void));
53 static int edit_istep
__P((IFILE
, int, int));
54 static int edit_inext
__P((IFILE
, int));
55 static int edit_iprev
__P((IFILE
, int));
58 * Textlist functions deal with a list of words separated by spaces.
59 * init_textlist sets up a textlist structure.
60 * forw_textlist uses that structure to iterate thru the list of
61 * words, returning each one as a standard null-terminated string.
62 * back_textlist does the same, but runs thru the list backwards.
65 init_textlist(tlist
, str
)
66 struct textlist
*tlist
;
70 #if SPACES_IN_FILENAMES
73 char *esc
= get_meta_escape();
74 int esclen
= strlen(esc
);
77 tlist
->string
= skipsp(str
);
78 tlist
->endstring
= tlist
->string
+ strlen(tlist
->string
);
79 for (s
= str
; s
< tlist
->endstring
; s
++)
81 #if SPACES_IN_FILENAMES
85 } else if (esclen
> 0 && s
+ esclen
< tlist
->endstring
&&
86 strncmp(s
, esc
, esclen
) == 0)
90 } else if (delim_quoted
)
94 } else /* (!delim_quoted) */
109 forw_textlist(tlist
, prev
)
110 struct textlist
*tlist
;
116 * prev == NULL means return the first word in the list.
117 * Otherwise, return the word after "prev".
122 s
= prev
+ strlen(prev
);
123 if (s
>= tlist
->endstring
)
127 if (s
>= tlist
->endstring
)
133 back_textlist(tlist
, prev
)
134 struct textlist
*tlist
;
140 * prev == NULL means return the last word in the list.
141 * Otherwise, return the word before "prev".
144 s
= tlist
->endstring
;
145 else if (prev
<= tlist
->string
)
151 if (s
<= tlist
->string
)
153 while (s
[-1] != '\0' && s
> tlist
->string
)
159 * Close the current input file.
164 struct scrpos scrpos
;
166 if (curr_ifile
== NULL_IFILE
)
170 * Save the current position so that we can return to
171 * the same position if we edit this file again.
174 if (scrpos
.pos
!= NULL_POSITION
)
176 store_pos(curr_ifile
, &scrpos
);
180 * Close the file descriptor, unless it is a pipe.
184 * If we opened a file using an alternate name,
185 * do special stuff to close it.
187 if (curr_altfilename
!= NULL
)
189 close_altfile(curr_altfilename
, get_filename(curr_ifile
),
191 free(curr_altfilename
);
192 curr_altfilename
= NULL
;
194 curr_ifile
= NULL_IFILE
;
196 curr_ino
= curr_dev
= 0;
201 * Edit a new file (given its name).
202 * Filename == "-" means standard input.
203 * Filename == NULL means just close the current file.
209 if (filename
== NULL
)
210 return (edit_ifile(NULL_IFILE
));
211 return (edit_ifile(get_ifile(filename
, curr_ifile
)));
215 * Edit a new file (given its IFILE).
216 * ifile == NULL means just close the current file.
228 char *qopen_filename
;
231 IFILE was_curr_ifile
;
234 if (ifile
== curr_ifile
)
237 * Already have the correct file open.
243 * We must close the currently open file now.
244 * This is necessary to make the open_altfile/close_altfile pairs
245 * nest properly (or rather to avoid nesting at all).
246 * {{ Some stupid implementations of popen() mess up if you do:
247 * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
252 was_curr_ifile
= save_curr_ifile();
253 if (curr_ifile
!= NULL_IFILE
)
255 chflags
= ch_getflags();
257 if ((chflags
& CH_HELPFILE
) && held_ifile(was_curr_ifile
) <= 1)
260 * Don't keep the help file in the ifile list.
262 del_ifile(was_curr_ifile
);
263 was_curr_ifile
= old_ifile
;
267 if (ifile
== NULL_IFILE
)
270 * No new file to open.
271 * (Don't set old_ifile, because if you call edit_ifile(NULL),
272 * you're supposed to have saved curr_ifile yourself,
273 * and you'll restore it if necessary.)
275 unsave_ifile(was_curr_ifile
);
279 filename
= save(get_filename(ifile
));
281 * See if LESSOPEN specifies an "alternate" file to open.
284 alt_filename
= open_altfile(filename
, &f
, &alt_pipe
);
285 open_filename
= (alt_filename
!= NULL
) ? alt_filename
: filename
;
286 qopen_filename
= shell_unquote(open_filename
);
289 if (alt_pipe
!= NULL
)
292 * The alternate "file" is actually a pipe.
293 * f has already been set to the file descriptor of the pipe
294 * in the call to open_altfile above.
295 * Keep the file descriptor open because it was opened
296 * via popen(), and pclose() wants to close it.
298 chflags
|= CH_POPENED
;
299 } else if (strcmp(open_filename
, "-") == 0)
302 * Use standard input.
303 * Keep the file descriptor open because we can't reopen it.
306 chflags
|= CH_KEEPOPEN
;
308 * Must switch stdin to BINARY mode.
311 #if MSDOS_COMPILER==DJGPPC
313 * Setting stdin to binary by default causes
314 * Ctrl-C to not raise SIGINT. We must undo
317 __djgpp_set_ctrl_c(1);
319 } else if (strcmp(open_filename
, FAKE_EMPTYFILE
) == 0)
322 chflags
|= CH_NODATA
;
323 } else if (strcmp(open_filename
, FAKE_HELPFILE
) == 0)
326 chflags
|= CH_HELPFILE
;
327 } else if ((parg
.p_string
= bad_file(open_filename
)) != NULL
)
330 * It looks like a bad file. Don't try to open it.
333 free((void *)parg
.p_string
);
335 if (alt_filename
!= NULL
)
337 close_altfile(alt_filename
, filename
, alt_pipe
);
341 free(qopen_filename
);
344 * Re-open the current file.
346 if (was_curr_ifile
== ifile
)
349 * Whoops. The "current" ifile is the one we just deleted.
354 reedit_ifile(was_curr_ifile
);
356 } else if ((f
= open(qopen_filename
, OPEN_READ
)) < 0)
359 * Got an error trying to open it.
361 parg
.p_string
= errno_message(filename
);
363 free((void *)parg
.p_string
);
367 chflags
|= CH_CANSEEK
;
368 if (!force_open
&& !opened(ifile
) && bin_file(f
))
371 * Looks like a binary file.
372 * Ask user if we should proceed.
374 parg
.p_string
= filename
;
375 answer
= query("\"%s\" may be a binary file. See it anyway? ",
377 if (answer
!= 'y' && answer
!= 'Y')
387 * Get the saved position for the file.
389 if (was_curr_ifile
!= NULL_IFILE
)
391 old_ifile
= was_curr_ifile
;
392 unsave_ifile(was_curr_ifile
);
395 curr_altfilename
= alt_filename
;
396 curr_altpipe
= alt_pipe
;
397 set_open(curr_ifile
); /* File has been opened */
398 get_pos(curr_ifile
, &initial_scrpos
);
402 if (!(chflags
& CH_HELPFILE
))
405 if (namelogfile
!= NULL
&& is_tty
)
406 use_logfile(namelogfile
);
409 /* Remember the i-number and device of the opened file. */
412 int r
= stat(qopen_filename
, &statbuf
);
415 curr_ino
= statbuf
.st_ino
;
416 curr_dev
= statbuf
.st_dev
;
420 if (every_first_cmd
!= NULL
)
421 ungetsc(every_first_cmd
);
424 free(qopen_filename
);
425 no_display
= !any_display
;
432 * Output is to a real tty.
436 * Indicate there is nothing displayed yet.
443 cmd_addhist(ml_examine
, filename
);
444 if (no_display
&& errmsgs
> 0)
447 * We displayed some messages on error output
448 * (file descriptor 2; see error() function).
449 * Before erasing the screen contents,
450 * display the file name and wait for a keystroke.
452 parg
.p_string
= filename
;
461 * Edit a space-separated list of files.
462 * For each filename in the list, enter it into the ifile list.
463 * Then edit the first one.
474 struct textlist tl_files
;
475 struct textlist tl_gfiles
;
477 save_ifile
= save_curr_ifile();
478 good_filename
= NULL
;
481 * Run thru each filename in the list.
482 * Try to glob the filename.
483 * If it doesn't expand, just try to open the filename.
484 * If it does expand, try to open each name in that list.
486 init_textlist(&tl_files
, filelist
);
488 while ((filename
= forw_textlist(&tl_files
, filename
)) != NULL
)
490 gfilelist
= lglob(filename
);
491 init_textlist(&tl_gfiles
, gfilelist
);
493 while ((gfilename
= forw_textlist(&tl_gfiles
, gfilename
)) != NULL
)
495 if (edit(gfilename
) == 0 && good_filename
== NULL
)
496 good_filename
= get_filename(curr_ifile
);
501 * Edit the first valid filename in the list.
503 if (good_filename
== NULL
)
505 unsave_ifile(save_ifile
);
508 if (get_ifile(good_filename
, curr_ifile
) == curr_ifile
)
511 * Trying to edit the current file; don't reopen it.
513 unsave_ifile(save_ifile
);
516 reedit_ifile(save_ifile
);
517 return (edit(good_filename
));
521 * Edit the first file in the command line (ifile) list.
526 curr_ifile
= NULL_IFILE
;
527 return (edit_next(1));
531 * Edit the last file in the command line (ifile) list.
536 curr_ifile
= NULL_IFILE
;
537 return (edit_prev(1));
542 * Edit the n-th next or previous file in the command line (ifile) list.
545 edit_istep(h
, n
, dir
)
553 * Skip n filenames, then try to edit each filename.
557 next
= (dir
> 0) ? next_ifile(h
) : prev_ifile(h
);
560 if (edit_ifile(h
) == 0)
563 if (next
== NULL_IFILE
)
566 * Reached end of the ifile list.
573 * Interrupt breaks out, if we're in a long
574 * list of files that can't be opened.
581 * Found a file that we can edit.
591 return (edit_istep(h
, n
, +1));
598 return edit_istep(curr_ifile
, n
, +1);
606 return (edit_istep(h
, n
, -1));
613 return edit_istep(curr_ifile
, n
, -1);
617 * Edit a specific file in the command line (ifile) list.
628 if ((h
= next_ifile(h
)) == NULL_IFILE
)
631 * Reached end of the list without finding it.
635 } while (get_index(h
) != n
);
637 return (edit_ifile(h
));
643 if (curr_ifile
!= NULL_IFILE
)
644 hold_ifile(curr_ifile
, 1);
649 unsave_ifile(save_ifile
)
652 if (save_ifile
!= NULL_IFILE
)
653 hold_ifile(save_ifile
, -1);
657 * Reedit the ifile which was previously open.
660 reedit_ifile(save_ifile
)
667 * Try to reopen the ifile.
668 * Note that opening it may fail (maybe the file was removed),
669 * in which case the ifile will be deleted from the list.
670 * So save the next and prev ifiles first.
672 unsave_ifile(save_ifile
);
673 next
= next_ifile(save_ifile
);
674 prev
= prev_ifile(save_ifile
);
675 if (edit_ifile(save_ifile
) == 0)
678 * If can't reopen it, open the next input file in the list.
680 if (next
!= NULL_IFILE
&& edit_inext(next
, 0) == 0)
683 * If can't open THAT one, open the previous input file in the list.
685 if (prev
!= NULL_IFILE
&& edit_iprev(prev
, 0) == 0)
688 * If can't even open that, we're stuck. Just quit.
696 IFILE save_ifile
= save_curr_ifile();
698 reedit_ifile(save_ifile
);
702 * Edit standard input.
709 error("Missing filename (\"less --help\" for help)", NULL_PARG
);
716 * Copy a file directly to standard output.
717 * Used if standard output is not a tty.
724 while ((c
= ch_forw_get()) != EOI
)
732 * If the user asked for a log file and our input file
733 * is standard input, create the log file.
734 * We take care not to blindly overwrite an existing file.
737 use_logfile(filename
)
744 if (ch_getflags() & CH_CANSEEK
)
746 * Can't currently use a log file on a file that can seek.
751 * {{ We could use access() here. }}
753 filename
= shell_unquote(filename
);
754 exists
= open(filename
, OPEN_READ
);
757 exists
= (exists
>= 0);
760 * Decide whether to overwrite the log file or append to it.
761 * If it doesn't exist we "overwrite" it.
763 if (!exists
|| force_logfile
)
766 * Overwrite (or create) the log file.
772 * Ask user what to do.
774 parg
.p_string
= filename
;
775 answer
= query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg
);
783 * Overwrite: create the file.
785 logfile
= creat(filename
, 0644);
789 * Append: open the file and seek to the end.
791 logfile
= open(filename
, OPEN_APPEND
);
792 if (lseek(logfile
, (off_t
)0, SEEK_END
) == BAD_LSEEK
)
811 answer
= query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG
);
818 * Error in opening logfile.
820 parg
.p_string
= filename
;
821 error("Cannot write to \"%s\"", &parg
);