11133e27eSPeter Avalos /*
2*320d7c8aSAaron LI * Copyright (C) 1984-2023 Mark Nudelman
31133e27eSPeter Avalos *
41133e27eSPeter Avalos * You may distribute under the terms of either the GNU General Public
51133e27eSPeter Avalos * License or the Less License, as specified in the README file.
61133e27eSPeter Avalos *
7e639dc31SJohn Marino * For more information, see the README file.
81133e27eSPeter Avalos */
91133e27eSPeter Avalos
101133e27eSPeter Avalos
111133e27eSPeter Avalos #include "less.h"
1202d62a0fSDaniel Fojt #include "position.h"
131133e27eSPeter Avalos #if HAVE_STAT
141133e27eSPeter Avalos #include <sys/stat.h>
151133e27eSPeter Avalos #endif
16*320d7c8aSAaron LI #if HAVE_SYS_WAIT_H
17*320d7c8aSAaron LI #include <sys/wait.h>
18*320d7c8aSAaron LI #endif
1902d62a0fSDaniel Fojt #include <signal.h>
201133e27eSPeter Avalos
211133e27eSPeter Avalos public int fd0 = 0;
221133e27eSPeter Avalos
231133e27eSPeter Avalos extern int new_file;
241133e27eSPeter Avalos extern int cbufs;
251133e27eSPeter Avalos extern char *every_first_cmd;
261133e27eSPeter Avalos extern int force_open;
271133e27eSPeter Avalos extern int is_tty;
281133e27eSPeter Avalos extern int sigs;
290c7ad07eSAntonio Huete Jimenez extern int hshift;
300c7ad07eSAntonio Huete Jimenez extern int want_filesize;
310c7ad07eSAntonio Huete Jimenez extern int consecutive_nulls;
32*320d7c8aSAaron LI extern int modelines;
33*320d7c8aSAaron LI extern int show_preproc_error;
341133e27eSPeter Avalos extern IFILE curr_ifile;
351133e27eSPeter Avalos extern IFILE old_ifile;
361133e27eSPeter Avalos extern struct scrpos initial_scrpos;
3702d62a0fSDaniel Fojt extern void *ml_examine;
381133e27eSPeter Avalos #if SPACES_IN_FILENAMES
391133e27eSPeter Avalos extern char openquote;
401133e27eSPeter Avalos extern char closequote;
411133e27eSPeter Avalos #endif
421133e27eSPeter Avalos
431133e27eSPeter Avalos #if LOGFILE
441133e27eSPeter Avalos extern int logfile;
451133e27eSPeter Avalos extern int force_logfile;
461133e27eSPeter Avalos extern char *namelogfile;
471133e27eSPeter Avalos #endif
481133e27eSPeter Avalos
491133e27eSPeter Avalos #if HAVE_STAT_INO
501133e27eSPeter Avalos public dev_t curr_dev;
511133e27eSPeter Avalos public ino_t curr_ino;
521133e27eSPeter Avalos #endif
531133e27eSPeter Avalos
541133e27eSPeter Avalos /*
551133e27eSPeter Avalos * Textlist functions deal with a list of words separated by spaces.
561133e27eSPeter Avalos * init_textlist sets up a textlist structure.
571133e27eSPeter Avalos * forw_textlist uses that structure to iterate thru the list of
581133e27eSPeter Avalos * words, returning each one as a standard null-terminated string.
591133e27eSPeter Avalos * back_textlist does the same, but runs thru the list backwards.
601133e27eSPeter Avalos */
init_textlist(struct textlist * tlist,char * str)61*320d7c8aSAaron LI public void init_textlist(struct textlist *tlist, char *str)
621133e27eSPeter Avalos {
631133e27eSPeter Avalos char *s;
641133e27eSPeter Avalos #if SPACES_IN_FILENAMES
651133e27eSPeter Avalos int meta_quoted = 0;
661133e27eSPeter Avalos int delim_quoted = 0;
671133e27eSPeter Avalos char *esc = get_meta_escape();
68fa0be7c5SJohn Marino int esclen = (int) strlen(esc);
691133e27eSPeter Avalos #endif
701133e27eSPeter Avalos
711133e27eSPeter Avalos tlist->string = skipsp(str);
721133e27eSPeter Avalos tlist->endstring = tlist->string + strlen(tlist->string);
731133e27eSPeter Avalos for (s = str; s < tlist->endstring; s++)
741133e27eSPeter Avalos {
751133e27eSPeter Avalos #if SPACES_IN_FILENAMES
761133e27eSPeter Avalos if (meta_quoted)
771133e27eSPeter Avalos {
781133e27eSPeter Avalos meta_quoted = 0;
791133e27eSPeter Avalos } else if (esclen > 0 && s + esclen < tlist->endstring &&
801133e27eSPeter Avalos strncmp(s, esc, esclen) == 0)
811133e27eSPeter Avalos {
821133e27eSPeter Avalos meta_quoted = 1;
831133e27eSPeter Avalos s += esclen - 1;
841133e27eSPeter Avalos } else if (delim_quoted)
851133e27eSPeter Avalos {
861133e27eSPeter Avalos if (*s == closequote)
871133e27eSPeter Avalos delim_quoted = 0;
881133e27eSPeter Avalos } else /* (!delim_quoted) */
891133e27eSPeter Avalos {
901133e27eSPeter Avalos if (*s == openquote)
911133e27eSPeter Avalos delim_quoted = 1;
921133e27eSPeter Avalos else if (*s == ' ')
931133e27eSPeter Avalos *s = '\0';
941133e27eSPeter Avalos }
951133e27eSPeter Avalos #else
961133e27eSPeter Avalos if (*s == ' ')
971133e27eSPeter Avalos *s = '\0';
981133e27eSPeter Avalos #endif
991133e27eSPeter Avalos }
1001133e27eSPeter Avalos }
1011133e27eSPeter Avalos
forw_textlist(struct textlist * tlist,char * prev)102*320d7c8aSAaron LI public char * forw_textlist(struct textlist *tlist, char *prev)
1031133e27eSPeter Avalos {
1041133e27eSPeter Avalos char *s;
1051133e27eSPeter Avalos
1061133e27eSPeter Avalos /*
1071133e27eSPeter Avalos * prev == NULL means return the first word in the list.
1081133e27eSPeter Avalos * Otherwise, return the word after "prev".
1091133e27eSPeter Avalos */
1101133e27eSPeter Avalos if (prev == NULL)
1111133e27eSPeter Avalos s = tlist->string;
1121133e27eSPeter Avalos else
1131133e27eSPeter Avalos s = prev + strlen(prev);
1141133e27eSPeter Avalos if (s >= tlist->endstring)
1151133e27eSPeter Avalos return (NULL);
1161133e27eSPeter Avalos while (*s == '\0')
1171133e27eSPeter Avalos s++;
1181133e27eSPeter Avalos if (s >= tlist->endstring)
1191133e27eSPeter Avalos return (NULL);
1201133e27eSPeter Avalos return (s);
1211133e27eSPeter Avalos }
1221133e27eSPeter Avalos
back_textlist(struct textlist * tlist,char * prev)123*320d7c8aSAaron LI public char * back_textlist(struct textlist *tlist, char *prev)
1241133e27eSPeter Avalos {
1251133e27eSPeter Avalos char *s;
1261133e27eSPeter Avalos
1271133e27eSPeter Avalos /*
1281133e27eSPeter Avalos * prev == NULL means return the last word in the list.
1291133e27eSPeter Avalos * Otherwise, return the word before "prev".
1301133e27eSPeter Avalos */
1311133e27eSPeter Avalos if (prev == NULL)
1321133e27eSPeter Avalos s = tlist->endstring;
1331133e27eSPeter Avalos else if (prev <= tlist->string)
1341133e27eSPeter Avalos return (NULL);
1351133e27eSPeter Avalos else
1361133e27eSPeter Avalos s = prev - 1;
1371133e27eSPeter Avalos while (*s == '\0')
1381133e27eSPeter Avalos s--;
1391133e27eSPeter Avalos if (s <= tlist->string)
1401133e27eSPeter Avalos return (NULL);
1411133e27eSPeter Avalos while (s[-1] != '\0' && s > tlist->string)
1421133e27eSPeter Avalos s--;
1431133e27eSPeter Avalos return (s);
1441133e27eSPeter Avalos }
1451133e27eSPeter Avalos
1461133e27eSPeter Avalos /*
147*320d7c8aSAaron LI * Parse a single option setting in a modeline.
148*320d7c8aSAaron LI */
modeline_option(char * str,int opt_len)149*320d7c8aSAaron LI static void modeline_option(char *str, int opt_len)
150*320d7c8aSAaron LI {
151*320d7c8aSAaron LI struct mloption { char *opt_name; void (*opt_func)(char*,int); };
152*320d7c8aSAaron LI struct mloption options[] = {
153*320d7c8aSAaron LI { "ts=", set_tabs },
154*320d7c8aSAaron LI { "tabstop=", set_tabs },
155*320d7c8aSAaron LI { NULL, NULL }
156*320d7c8aSAaron LI };
157*320d7c8aSAaron LI struct mloption *opt;
158*320d7c8aSAaron LI for (opt = options; opt->opt_name != NULL; opt++)
159*320d7c8aSAaron LI {
160*320d7c8aSAaron LI int name_len = strlen(opt->opt_name);
161*320d7c8aSAaron LI if (opt_len > name_len && strncmp(str, opt->opt_name, name_len) == 0)
162*320d7c8aSAaron LI {
163*320d7c8aSAaron LI (*opt->opt_func)(str + name_len, opt_len - name_len);
164*320d7c8aSAaron LI break;
165*320d7c8aSAaron LI }
166*320d7c8aSAaron LI }
167*320d7c8aSAaron LI }
168*320d7c8aSAaron LI
169*320d7c8aSAaron LI /*
170*320d7c8aSAaron LI * String length, terminated by option separator (space or colon).
171*320d7c8aSAaron LI * Space/colon can be escaped with backspace.
172*320d7c8aSAaron LI */
modeline_option_len(char * str)173*320d7c8aSAaron LI static int modeline_option_len(char *str)
174*320d7c8aSAaron LI {
175*320d7c8aSAaron LI int esc = FALSE;
176*320d7c8aSAaron LI char *s;
177*320d7c8aSAaron LI for (s = str; *s != '\0'; s++)
178*320d7c8aSAaron LI {
179*320d7c8aSAaron LI if (esc)
180*320d7c8aSAaron LI esc = FALSE;
181*320d7c8aSAaron LI else if (*s == '\\')
182*320d7c8aSAaron LI esc = TRUE;
183*320d7c8aSAaron LI else if (*s == ' ' || *s == ':') /* separator */
184*320d7c8aSAaron LI break;
185*320d7c8aSAaron LI }
186*320d7c8aSAaron LI return (s - str);
187*320d7c8aSAaron LI }
188*320d7c8aSAaron LI
189*320d7c8aSAaron LI /*
190*320d7c8aSAaron LI * Parse colon- or space-separated option settings in a modeline.
191*320d7c8aSAaron LI */
modeline_options(char * str,char end_char)192*320d7c8aSAaron LI static void modeline_options(char *str, char end_char)
193*320d7c8aSAaron LI {
194*320d7c8aSAaron LI for (;;)
195*320d7c8aSAaron LI {
196*320d7c8aSAaron LI int opt_len;
197*320d7c8aSAaron LI str = skipsp(str);
198*320d7c8aSAaron LI if (*str == '\0' || *str == end_char)
199*320d7c8aSAaron LI break;
200*320d7c8aSAaron LI opt_len = modeline_option_len(str);
201*320d7c8aSAaron LI modeline_option(str, opt_len);
202*320d7c8aSAaron LI str += opt_len;
203*320d7c8aSAaron LI if (*str != '\0')
204*320d7c8aSAaron LI str += 1; /* skip past the separator */
205*320d7c8aSAaron LI }
206*320d7c8aSAaron LI }
207*320d7c8aSAaron LI
208*320d7c8aSAaron LI /*
209*320d7c8aSAaron LI * See if there is a modeline string in a line.
210*320d7c8aSAaron LI */
check_modeline(char * line)211*320d7c8aSAaron LI static void check_modeline(char *line)
212*320d7c8aSAaron LI {
213*320d7c8aSAaron LI #if HAVE_STRSTR
214*320d7c8aSAaron LI static char *pgms[] = { "less:", "vim:", "vi:", "ex:", NULL };
215*320d7c8aSAaron LI char **pgm;
216*320d7c8aSAaron LI for (pgm = pgms; *pgm != NULL; ++pgm)
217*320d7c8aSAaron LI {
218*320d7c8aSAaron LI char *pline = line;
219*320d7c8aSAaron LI for (;;)
220*320d7c8aSAaron LI {
221*320d7c8aSAaron LI char *str;
222*320d7c8aSAaron LI pline = strstr(pline, *pgm);
223*320d7c8aSAaron LI if (pline == NULL) /* pgm is not in this line */
224*320d7c8aSAaron LI break;
225*320d7c8aSAaron LI str = skipsp(pline + strlen(*pgm));
226*320d7c8aSAaron LI if (pline == line || pline[-1] == ' ')
227*320d7c8aSAaron LI {
228*320d7c8aSAaron LI if (strncmp(str, "set ", 4) == 0)
229*320d7c8aSAaron LI modeline_options(str+4, ':');
230*320d7c8aSAaron LI else if (pgm != &pgms[0]) /* "less:" requires "set" */
231*320d7c8aSAaron LI modeline_options(str, '\0');
232*320d7c8aSAaron LI break;
233*320d7c8aSAaron LI }
234*320d7c8aSAaron LI /* Continue searching the rest of the line. */
235*320d7c8aSAaron LI pline = str;
236*320d7c8aSAaron LI }
237*320d7c8aSAaron LI }
238*320d7c8aSAaron LI #endif /* HAVE_STRSTR */
239*320d7c8aSAaron LI }
240*320d7c8aSAaron LI
241*320d7c8aSAaron LI /*
242*320d7c8aSAaron LI * Read lines from start of file and check if any are modelines.
243*320d7c8aSAaron LI */
check_modelines(void)244*320d7c8aSAaron LI static void check_modelines(void)
245*320d7c8aSAaron LI {
246*320d7c8aSAaron LI POSITION pos = ch_zero();
247*320d7c8aSAaron LI int i;
248*320d7c8aSAaron LI for (i = 0; i < modelines; i++)
249*320d7c8aSAaron LI {
250*320d7c8aSAaron LI char *line;
251*320d7c8aSAaron LI int line_len;
252*320d7c8aSAaron LI if (ABORT_SIGS())
253*320d7c8aSAaron LI return;
254*320d7c8aSAaron LI pos = forw_raw_line(pos, &line, &line_len);
255*320d7c8aSAaron LI if (pos == NULL_POSITION)
256*320d7c8aSAaron LI break;
257*320d7c8aSAaron LI check_modeline(line);
258*320d7c8aSAaron LI }
259*320d7c8aSAaron LI }
260*320d7c8aSAaron LI
261*320d7c8aSAaron LI /*
26202d62a0fSDaniel Fojt * Close a pipe opened via popen.
26302d62a0fSDaniel Fojt */
close_pipe(FILE * pipefd)264*320d7c8aSAaron LI static void close_pipe(FILE *pipefd)
26502d62a0fSDaniel Fojt {
266*320d7c8aSAaron LI int status;
267*320d7c8aSAaron LI PARG parg;
268*320d7c8aSAaron LI
26902d62a0fSDaniel Fojt if (pipefd == NULL)
27002d62a0fSDaniel Fojt return;
27102d62a0fSDaniel Fojt #if OS2
27202d62a0fSDaniel Fojt /*
27302d62a0fSDaniel Fojt * The pclose function of OS/2 emx sometimes fails.
27402d62a0fSDaniel Fojt * Send SIGINT to the piped process before closing it.
27502d62a0fSDaniel Fojt */
27602d62a0fSDaniel Fojt kill(pipefd->_pid, SIGINT);
27702d62a0fSDaniel Fojt #endif
278*320d7c8aSAaron LI status = pclose(pipefd);
279*320d7c8aSAaron LI if (status == -1)
280*320d7c8aSAaron LI {
281*320d7c8aSAaron LI /* An internal error in 'less', not a preprocessor error. */
282*320d7c8aSAaron LI parg.p_string = errno_message("pclose");
283*320d7c8aSAaron LI error("%s", &parg);
284*320d7c8aSAaron LI free(parg.p_string);
285*320d7c8aSAaron LI return;
286*320d7c8aSAaron LI }
287*320d7c8aSAaron LI if (!show_preproc_error)
288*320d7c8aSAaron LI return;
289*320d7c8aSAaron LI #if defined WIFEXITED && defined WEXITSTATUS
290*320d7c8aSAaron LI if (WIFEXITED(status))
291*320d7c8aSAaron LI {
292*320d7c8aSAaron LI int s = WEXITSTATUS(status);
293*320d7c8aSAaron LI if (s != 0)
294*320d7c8aSAaron LI {
295*320d7c8aSAaron LI parg.p_int = s;
296*320d7c8aSAaron LI error("Input preprocessor failed (status %d)", &parg);
297*320d7c8aSAaron LI }
298*320d7c8aSAaron LI return;
299*320d7c8aSAaron LI }
300*320d7c8aSAaron LI #endif
301*320d7c8aSAaron LI #if defined WIFSIGNALED && defined WTERMSIG && HAVE_STRSIGNAL
302*320d7c8aSAaron LI if (WIFSIGNALED(status))
303*320d7c8aSAaron LI {
304*320d7c8aSAaron LI int sig = WTERMSIG(status);
305*320d7c8aSAaron LI if (sig != SIGPIPE || ch_length() != NULL_POSITION)
306*320d7c8aSAaron LI {
307*320d7c8aSAaron LI parg.p_string = signal_message(sig);
308*320d7c8aSAaron LI error("Input preprocessor terminated: %s", &parg);
309*320d7c8aSAaron LI }
310*320d7c8aSAaron LI return;
311*320d7c8aSAaron LI }
312*320d7c8aSAaron LI #endif
313*320d7c8aSAaron LI if (status != 0)
314*320d7c8aSAaron LI {
315*320d7c8aSAaron LI parg.p_int = status;
316*320d7c8aSAaron LI error("Input preprocessor exited with status %x", &parg);
317*320d7c8aSAaron LI }
318*320d7c8aSAaron LI }
319*320d7c8aSAaron LI
320*320d7c8aSAaron LI /*
321*320d7c8aSAaron LI * Drain and close an input pipe if needed.
322*320d7c8aSAaron LI */
close_altpipe(IFILE ifile)323*320d7c8aSAaron LI public void close_altpipe(IFILE ifile)
324*320d7c8aSAaron LI {
325*320d7c8aSAaron LI FILE *altpipe = get_altpipe(ifile);
326*320d7c8aSAaron LI if (altpipe != NULL && !(ch_getflags() & CH_KEEPOPEN))
327*320d7c8aSAaron LI {
328*320d7c8aSAaron LI close_pipe(altpipe);
329*320d7c8aSAaron LI set_altpipe(ifile, NULL);
330*320d7c8aSAaron LI }
331*320d7c8aSAaron LI }
332*320d7c8aSAaron LI
333*320d7c8aSAaron LI /*
334*320d7c8aSAaron LI * Check for error status from the current altpipe.
335*320d7c8aSAaron LI * May or may not close the pipe.
336*320d7c8aSAaron LI */
check_altpipe_error(void)337*320d7c8aSAaron LI public void check_altpipe_error(void)
338*320d7c8aSAaron LI {
339*320d7c8aSAaron LI if (!show_preproc_error)
340*320d7c8aSAaron LI return;
341*320d7c8aSAaron LI if (curr_ifile != NULL_IFILE && get_altfilename(curr_ifile) != NULL)
342*320d7c8aSAaron LI close_altpipe(curr_ifile);
34302d62a0fSDaniel Fojt }
34402d62a0fSDaniel Fojt
34502d62a0fSDaniel Fojt /*
3461133e27eSPeter Avalos * Close the current input file.
3471133e27eSPeter Avalos */
close_file(void)348*320d7c8aSAaron LI static void close_file(void)
3491133e27eSPeter Avalos {
3501133e27eSPeter Avalos struct scrpos scrpos;
35102d62a0fSDaniel Fojt char *altfilename;
3521133e27eSPeter Avalos
3531133e27eSPeter Avalos if (curr_ifile == NULL_IFILE)
3541133e27eSPeter Avalos return;
3551133e27eSPeter Avalos
3561133e27eSPeter Avalos /*
3571133e27eSPeter Avalos * Save the current position so that we can return to
3581133e27eSPeter Avalos * the same position if we edit this file again.
3591133e27eSPeter Avalos */
36002d62a0fSDaniel Fojt get_scrpos(&scrpos, TOP);
3611133e27eSPeter Avalos if (scrpos.pos != NULL_POSITION)
3621133e27eSPeter Avalos {
3631133e27eSPeter Avalos store_pos(curr_ifile, &scrpos);
3641133e27eSPeter Avalos lastmark();
3651133e27eSPeter Avalos }
3661133e27eSPeter Avalos /*
3671133e27eSPeter Avalos * Close the file descriptor, unless it is a pipe.
3681133e27eSPeter Avalos */
3691133e27eSPeter Avalos ch_close();
3701133e27eSPeter Avalos /*
3711133e27eSPeter Avalos * If we opened a file using an alternate name,
3721133e27eSPeter Avalos * do special stuff to close it.
3731133e27eSPeter Avalos */
37402d62a0fSDaniel Fojt altfilename = get_altfilename(curr_ifile);
37502d62a0fSDaniel Fojt if (altfilename != NULL)
3761133e27eSPeter Avalos {
377*320d7c8aSAaron LI close_altpipe(curr_ifile);
37802d62a0fSDaniel Fojt close_altfile(altfilename, get_filename(curr_ifile));
37902d62a0fSDaniel Fojt set_altfilename(curr_ifile, NULL);
3801133e27eSPeter Avalos }
3811133e27eSPeter Avalos curr_ifile = NULL_IFILE;
3821133e27eSPeter Avalos #if HAVE_STAT_INO
3831133e27eSPeter Avalos curr_ino = curr_dev = 0;
3841133e27eSPeter Avalos #endif
3851133e27eSPeter Avalos }
3861133e27eSPeter Avalos
3871133e27eSPeter Avalos /*
3881133e27eSPeter Avalos * Edit a new file (given its name).
3891133e27eSPeter Avalos * Filename == "-" means standard input.
3901133e27eSPeter Avalos * Filename == NULL means just close the current file.
3911133e27eSPeter Avalos */
edit(char * filename)392*320d7c8aSAaron LI public int edit(char *filename)
3931133e27eSPeter Avalos {
3941133e27eSPeter Avalos if (filename == NULL)
3951133e27eSPeter Avalos return (edit_ifile(NULL_IFILE));
3961133e27eSPeter Avalos return (edit_ifile(get_ifile(filename, curr_ifile)));
3971133e27eSPeter Avalos }
3981133e27eSPeter Avalos
3991133e27eSPeter Avalos /*
400*320d7c8aSAaron LI * Clean up what edit_ifile did before error return.
401*320d7c8aSAaron LI */
edit_error(char * filename,char * alt_filename,void * altpipe,IFILE ifile,IFILE was_curr_ifile)402*320d7c8aSAaron LI static int edit_error(char *filename, char *alt_filename, void *altpipe, IFILE ifile, IFILE was_curr_ifile)
403*320d7c8aSAaron LI {
404*320d7c8aSAaron LI if (alt_filename != NULL)
405*320d7c8aSAaron LI {
406*320d7c8aSAaron LI close_pipe(altpipe);
407*320d7c8aSAaron LI close_altfile(alt_filename, filename);
408*320d7c8aSAaron LI free(alt_filename);
409*320d7c8aSAaron LI }
410*320d7c8aSAaron LI del_ifile(ifile);
411*320d7c8aSAaron LI free(filename);
412*320d7c8aSAaron LI /*
413*320d7c8aSAaron LI * Re-open the current file.
414*320d7c8aSAaron LI */
415*320d7c8aSAaron LI if (was_curr_ifile == ifile)
416*320d7c8aSAaron LI {
417*320d7c8aSAaron LI /*
418*320d7c8aSAaron LI * Whoops. The "current" ifile is the one we just deleted.
419*320d7c8aSAaron LI * Just give up.
420*320d7c8aSAaron LI */
421*320d7c8aSAaron LI quit(QUIT_ERROR);
422*320d7c8aSAaron LI }
423*320d7c8aSAaron LI reedit_ifile(was_curr_ifile);
424*320d7c8aSAaron LI return (1);
425*320d7c8aSAaron LI }
426*320d7c8aSAaron LI
427*320d7c8aSAaron LI /*
4281133e27eSPeter Avalos * Edit a new file (given its IFILE).
4291133e27eSPeter Avalos * ifile == NULL means just close the current file.
4301133e27eSPeter Avalos */
edit_ifile(IFILE ifile)431*320d7c8aSAaron LI public int edit_ifile(IFILE ifile)
4321133e27eSPeter Avalos {
4331133e27eSPeter Avalos int f;
4341133e27eSPeter Avalos int answer;
4351133e27eSPeter Avalos int chflags;
4361133e27eSPeter Avalos char *filename;
4371133e27eSPeter Avalos char *open_filename;
4381133e27eSPeter Avalos char *alt_filename;
43902d62a0fSDaniel Fojt void *altpipe;
4401133e27eSPeter Avalos IFILE was_curr_ifile;
4411133e27eSPeter Avalos PARG parg;
4421133e27eSPeter Avalos
4431133e27eSPeter Avalos if (ifile == curr_ifile)
4441133e27eSPeter Avalos {
4451133e27eSPeter Avalos /*
4461133e27eSPeter Avalos * Already have the correct file open.
4471133e27eSPeter Avalos */
4481133e27eSPeter Avalos return (0);
4491133e27eSPeter Avalos }
4501133e27eSPeter Avalos
4511133e27eSPeter Avalos /*
4521133e27eSPeter Avalos * We must close the currently open file now.
4531133e27eSPeter Avalos * This is necessary to make the open_altfile/close_altfile pairs
4541133e27eSPeter Avalos * nest properly (or rather to avoid nesting at all).
4551133e27eSPeter Avalos * {{ Some stupid implementations of popen() mess up if you do:
4561133e27eSPeter Avalos * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
4571133e27eSPeter Avalos */
4581133e27eSPeter Avalos #if LOGFILE
4591133e27eSPeter Avalos end_logfile();
4601133e27eSPeter Avalos #endif
4611133e27eSPeter Avalos was_curr_ifile = save_curr_ifile();
4621133e27eSPeter Avalos if (curr_ifile != NULL_IFILE)
4631133e27eSPeter Avalos {
4641133e27eSPeter Avalos chflags = ch_getflags();
4651133e27eSPeter Avalos close_file();
4661133e27eSPeter Avalos if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
4671133e27eSPeter Avalos {
4681133e27eSPeter Avalos /*
4691133e27eSPeter Avalos * Don't keep the help file in the ifile list.
4701133e27eSPeter Avalos */
4711133e27eSPeter Avalos del_ifile(was_curr_ifile);
4721133e27eSPeter Avalos was_curr_ifile = old_ifile;
4731133e27eSPeter Avalos }
4741133e27eSPeter Avalos }
4751133e27eSPeter Avalos
4761133e27eSPeter Avalos if (ifile == NULL_IFILE)
4771133e27eSPeter Avalos {
4781133e27eSPeter Avalos /*
4791133e27eSPeter Avalos * No new file to open.
4801133e27eSPeter Avalos * (Don't set old_ifile, because if you call edit_ifile(NULL),
4811133e27eSPeter Avalos * you're supposed to have saved curr_ifile yourself,
4821133e27eSPeter Avalos * and you'll restore it if necessary.)
4831133e27eSPeter Avalos */
4841133e27eSPeter Avalos unsave_ifile(was_curr_ifile);
4851133e27eSPeter Avalos return (0);
4861133e27eSPeter Avalos }
4871133e27eSPeter Avalos
4881133e27eSPeter Avalos filename = save(get_filename(ifile));
48902d62a0fSDaniel Fojt
4901133e27eSPeter Avalos /*
4911133e27eSPeter Avalos * See if LESSOPEN specifies an "alternate" file to open.
4921133e27eSPeter Avalos */
49302d62a0fSDaniel Fojt altpipe = get_altpipe(ifile);
49402d62a0fSDaniel Fojt if (altpipe != NULL)
49502d62a0fSDaniel Fojt {
49602d62a0fSDaniel Fojt /*
49702d62a0fSDaniel Fojt * File is already open.
49802d62a0fSDaniel Fojt * chflags and f are not used by ch_init if ifile has
49902d62a0fSDaniel Fojt * filestate which should be the case if we're here.
50002d62a0fSDaniel Fojt * Set them here to avoid uninitialized variable warnings.
50102d62a0fSDaniel Fojt */
50202d62a0fSDaniel Fojt chflags = 0;
50302d62a0fSDaniel Fojt f = -1;
50402d62a0fSDaniel Fojt alt_filename = get_altfilename(ifile);
5051133e27eSPeter Avalos open_filename = (alt_filename != NULL) ? alt_filename : filename;
50602d62a0fSDaniel Fojt } else
50702d62a0fSDaniel Fojt {
50802d62a0fSDaniel Fojt if (strcmp(filename, FAKE_HELPFILE) == 0 ||
50902d62a0fSDaniel Fojt strcmp(filename, FAKE_EMPTYFILE) == 0)
51002d62a0fSDaniel Fojt alt_filename = NULL;
51102d62a0fSDaniel Fojt else
51202d62a0fSDaniel Fojt alt_filename = open_altfile(filename, &f, &altpipe);
51302d62a0fSDaniel Fojt
51402d62a0fSDaniel Fojt open_filename = (alt_filename != NULL) ? alt_filename : filename;
5151133e27eSPeter Avalos
5161133e27eSPeter Avalos chflags = 0;
51702d62a0fSDaniel Fojt if (altpipe != NULL)
5181133e27eSPeter Avalos {
5191133e27eSPeter Avalos /*
5201133e27eSPeter Avalos * The alternate "file" is actually a pipe.
5211133e27eSPeter Avalos * f has already been set to the file descriptor of the pipe
5221133e27eSPeter Avalos * in the call to open_altfile above.
5231133e27eSPeter Avalos * Keep the file descriptor open because it was opened
5241133e27eSPeter Avalos * via popen(), and pclose() wants to close it.
5251133e27eSPeter Avalos */
5261133e27eSPeter Avalos chflags |= CH_POPENED;
52702d62a0fSDaniel Fojt if (strcmp(filename, "-") == 0)
52802d62a0fSDaniel Fojt chflags |= CH_KEEPOPEN;
52902d62a0fSDaniel Fojt } else if (strcmp(filename, "-") == 0)
5301133e27eSPeter Avalos {
5311133e27eSPeter Avalos /*
5321133e27eSPeter Avalos * Use standard input.
5331133e27eSPeter Avalos * Keep the file descriptor open because we can't reopen it.
5341133e27eSPeter Avalos */
5351133e27eSPeter Avalos f = fd0;
5361133e27eSPeter Avalos chflags |= CH_KEEPOPEN;
5371133e27eSPeter Avalos /*
5381133e27eSPeter Avalos * Must switch stdin to BINARY mode.
5391133e27eSPeter Avalos */
5401133e27eSPeter Avalos SET_BINARY(f);
5411133e27eSPeter Avalos #if MSDOS_COMPILER==DJGPPC
5421133e27eSPeter Avalos /*
5431133e27eSPeter Avalos * Setting stdin to binary by default causes
5441133e27eSPeter Avalos * Ctrl-C to not raise SIGINT. We must undo
5451133e27eSPeter Avalos * that side-effect.
5461133e27eSPeter Avalos */
5471133e27eSPeter Avalos __djgpp_set_ctrl_c(1);
5481133e27eSPeter Avalos #endif
549e639dc31SJohn Marino } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
550e639dc31SJohn Marino {
551e639dc31SJohn Marino f = -1;
552e639dc31SJohn Marino chflags |= CH_NODATA;
5531133e27eSPeter Avalos } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
5541133e27eSPeter Avalos {
5551133e27eSPeter Avalos f = -1;
5561133e27eSPeter Avalos chflags |= CH_HELPFILE;
5571133e27eSPeter Avalos } else if ((parg.p_string = bad_file(open_filename)) != NULL)
5581133e27eSPeter Avalos {
5591133e27eSPeter Avalos /*
5601133e27eSPeter Avalos * It looks like a bad file. Don't try to open it.
5611133e27eSPeter Avalos */
5621133e27eSPeter Avalos error("%s", &parg);
5631133e27eSPeter Avalos free(parg.p_string);
564*320d7c8aSAaron LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
56502d62a0fSDaniel Fojt } else if ((f = open(open_filename, OPEN_READ)) < 0)
5661133e27eSPeter Avalos {
5671133e27eSPeter Avalos /*
5681133e27eSPeter Avalos * Got an error trying to open it.
5691133e27eSPeter Avalos */
5701133e27eSPeter Avalos parg.p_string = errno_message(filename);
5711133e27eSPeter Avalos error("%s", &parg);
5721133e27eSPeter Avalos free(parg.p_string);
573*320d7c8aSAaron LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
5741133e27eSPeter Avalos } else
5751133e27eSPeter Avalos {
5761133e27eSPeter Avalos chflags |= CH_CANSEEK;
5771133e27eSPeter Avalos if (!force_open && !opened(ifile) && bin_file(f))
5781133e27eSPeter Avalos {
5791133e27eSPeter Avalos /*
5801133e27eSPeter Avalos * Looks like a binary file.
5811133e27eSPeter Avalos * Ask user if we should proceed.
5821133e27eSPeter Avalos */
5831133e27eSPeter Avalos parg.p_string = filename;
5841133e27eSPeter Avalos answer = query("\"%s\" may be a binary file. See it anyway? ",
5851133e27eSPeter Avalos &parg);
5861133e27eSPeter Avalos if (answer != 'y' && answer != 'Y')
5871133e27eSPeter Avalos {
5881133e27eSPeter Avalos close(f);
589*320d7c8aSAaron LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
5901133e27eSPeter Avalos }
5911133e27eSPeter Avalos }
5921133e27eSPeter Avalos }
59302d62a0fSDaniel Fojt }
594*320d7c8aSAaron LI if (!force_open && f >= 0 && isatty(f))
595*320d7c8aSAaron LI {
596*320d7c8aSAaron LI PARG parg;
597*320d7c8aSAaron LI parg.p_string = filename;
598*320d7c8aSAaron LI error("%s is a terminal (use -f to open it)", &parg);
599*320d7c8aSAaron LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
600*320d7c8aSAaron LI }
6011133e27eSPeter Avalos
6021133e27eSPeter Avalos /*
6031133e27eSPeter Avalos * Get the new ifile.
6041133e27eSPeter Avalos * Get the saved position for the file.
6051133e27eSPeter Avalos */
6061133e27eSPeter Avalos if (was_curr_ifile != NULL_IFILE)
6071133e27eSPeter Avalos {
6081133e27eSPeter Avalos old_ifile = was_curr_ifile;
6091133e27eSPeter Avalos unsave_ifile(was_curr_ifile);
6101133e27eSPeter Avalos }
6111133e27eSPeter Avalos curr_ifile = ifile;
61202d62a0fSDaniel Fojt set_altfilename(curr_ifile, alt_filename);
61302d62a0fSDaniel Fojt set_altpipe(curr_ifile, altpipe);
6141133e27eSPeter Avalos set_open(curr_ifile); /* File has been opened */
6151133e27eSPeter Avalos get_pos(curr_ifile, &initial_scrpos);
6161133e27eSPeter Avalos new_file = TRUE;
6171133e27eSPeter Avalos ch_init(f, chflags);
6180c7ad07eSAntonio Huete Jimenez consecutive_nulls = 0;
619*320d7c8aSAaron LI check_modelines();
6201133e27eSPeter Avalos
6211133e27eSPeter Avalos if (!(chflags & CH_HELPFILE))
6221133e27eSPeter Avalos {
6231133e27eSPeter Avalos #if LOGFILE
6241133e27eSPeter Avalos if (namelogfile != NULL && is_tty)
6251133e27eSPeter Avalos use_logfile(namelogfile);
6261133e27eSPeter Avalos #endif
6271133e27eSPeter Avalos #if HAVE_STAT_INO
6281133e27eSPeter Avalos /* Remember the i-number and device of the opened file. */
62902d62a0fSDaniel Fojt if (strcmp(open_filename, "-") != 0)
6301133e27eSPeter Avalos {
6311133e27eSPeter Avalos struct stat statbuf;
63202d62a0fSDaniel Fojt int r = stat(open_filename, &statbuf);
6331133e27eSPeter Avalos if (r == 0)
6341133e27eSPeter Avalos {
6351133e27eSPeter Avalos curr_ino = statbuf.st_ino;
6361133e27eSPeter Avalos curr_dev = statbuf.st_dev;
6371133e27eSPeter Avalos }
6381133e27eSPeter Avalos }
6391133e27eSPeter Avalos #endif
6401133e27eSPeter Avalos if (every_first_cmd != NULL)
641fa0be7c5SJohn Marino {
6421133e27eSPeter Avalos ungetsc(every_first_cmd);
6430c7ad07eSAntonio Huete Jimenez ungetcc_back(CHAR_END_COMMAND);
6441133e27eSPeter Avalos }
645fa0be7c5SJohn Marino }
6461133e27eSPeter Avalos
6471133e27eSPeter Avalos flush();
6481133e27eSPeter Avalos
6491133e27eSPeter Avalos if (is_tty)
6501133e27eSPeter Avalos {
6511133e27eSPeter Avalos /*
6521133e27eSPeter Avalos * Output is to a real tty.
6531133e27eSPeter Avalos */
6541133e27eSPeter Avalos
6551133e27eSPeter Avalos /*
6561133e27eSPeter Avalos * Indicate there is nothing displayed yet.
6571133e27eSPeter Avalos */
6581133e27eSPeter Avalos pos_clear();
6591133e27eSPeter Avalos clr_linenum();
6601133e27eSPeter Avalos #if HILITE_SEARCH
6611133e27eSPeter Avalos clr_hilite();
6621133e27eSPeter Avalos #endif
6630c7ad07eSAntonio Huete Jimenez hshift = 0;
6649b760066SJohn Marino if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE))
66502d62a0fSDaniel Fojt {
66602d62a0fSDaniel Fojt char *qfilename = shell_quote(filename);
66702d62a0fSDaniel Fojt cmd_addhist(ml_examine, qfilename, 1);
66802d62a0fSDaniel Fojt free(qfilename);
66902d62a0fSDaniel Fojt }
6700c7ad07eSAntonio Huete Jimenez if (want_filesize)
6710c7ad07eSAntonio Huete Jimenez scan_eof();
6721133e27eSPeter Avalos }
6731133e27eSPeter Avalos free(filename);
6741133e27eSPeter Avalos return (0);
6751133e27eSPeter Avalos }
6761133e27eSPeter Avalos
6771133e27eSPeter Avalos /*
6781133e27eSPeter Avalos * Edit a space-separated list of files.
6791133e27eSPeter Avalos * For each filename in the list, enter it into the ifile list.
6801133e27eSPeter Avalos * Then edit the first one.
6811133e27eSPeter Avalos */
edit_list(char * filelist)682*320d7c8aSAaron LI public int edit_list(char *filelist)
6831133e27eSPeter Avalos {
6841133e27eSPeter Avalos IFILE save_ifile;
6851133e27eSPeter Avalos char *good_filename;
6861133e27eSPeter Avalos char *filename;
6871133e27eSPeter Avalos char *gfilelist;
6881133e27eSPeter Avalos char *gfilename;
68902d62a0fSDaniel Fojt char *qfilename;
6901133e27eSPeter Avalos struct textlist tl_files;
6911133e27eSPeter Avalos struct textlist tl_gfiles;
6921133e27eSPeter Avalos
6931133e27eSPeter Avalos save_ifile = save_curr_ifile();
6941133e27eSPeter Avalos good_filename = NULL;
6951133e27eSPeter Avalos
6961133e27eSPeter Avalos /*
6971133e27eSPeter Avalos * Run thru each filename in the list.
6981133e27eSPeter Avalos * Try to glob the filename.
6991133e27eSPeter Avalos * If it doesn't expand, just try to open the filename.
7001133e27eSPeter Avalos * If it does expand, try to open each name in that list.
7011133e27eSPeter Avalos */
7021133e27eSPeter Avalos init_textlist(&tl_files, filelist);
7031133e27eSPeter Avalos filename = NULL;
7041133e27eSPeter Avalos while ((filename = forw_textlist(&tl_files, filename)) != NULL)
7051133e27eSPeter Avalos {
7061133e27eSPeter Avalos gfilelist = lglob(filename);
7071133e27eSPeter Avalos init_textlist(&tl_gfiles, gfilelist);
7081133e27eSPeter Avalos gfilename = NULL;
7091133e27eSPeter Avalos while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
7101133e27eSPeter Avalos {
71102d62a0fSDaniel Fojt qfilename = shell_unquote(gfilename);
71202d62a0fSDaniel Fojt if (edit(qfilename) == 0 && good_filename == NULL)
7131133e27eSPeter Avalos good_filename = get_filename(curr_ifile);
71402d62a0fSDaniel Fojt free(qfilename);
7151133e27eSPeter Avalos }
7161133e27eSPeter Avalos free(gfilelist);
7171133e27eSPeter Avalos }
7181133e27eSPeter Avalos /*
7191133e27eSPeter Avalos * Edit the first valid filename in the list.
7201133e27eSPeter Avalos */
7211133e27eSPeter Avalos if (good_filename == NULL)
7221133e27eSPeter Avalos {
7231133e27eSPeter Avalos unsave_ifile(save_ifile);
7241133e27eSPeter Avalos return (1);
7251133e27eSPeter Avalos }
7261133e27eSPeter Avalos if (get_ifile(good_filename, curr_ifile) == curr_ifile)
7271133e27eSPeter Avalos {
7281133e27eSPeter Avalos /*
7291133e27eSPeter Avalos * Trying to edit the current file; don't reopen it.
7301133e27eSPeter Avalos */
7311133e27eSPeter Avalos unsave_ifile(save_ifile);
7321133e27eSPeter Avalos return (0);
7331133e27eSPeter Avalos }
7341133e27eSPeter Avalos reedit_ifile(save_ifile);
7351133e27eSPeter Avalos return (edit(good_filename));
7361133e27eSPeter Avalos }
7371133e27eSPeter Avalos
7381133e27eSPeter Avalos /*
7391133e27eSPeter Avalos * Edit the first file in the command line (ifile) list.
7401133e27eSPeter Avalos */
edit_first(void)741*320d7c8aSAaron LI public int edit_first(void)
7421133e27eSPeter Avalos {
74302d62a0fSDaniel Fojt if (nifile() == 0)
74402d62a0fSDaniel Fojt return (edit_stdin());
7451133e27eSPeter Avalos curr_ifile = NULL_IFILE;
7461133e27eSPeter Avalos return (edit_next(1));
7471133e27eSPeter Avalos }
7481133e27eSPeter Avalos
7491133e27eSPeter Avalos /*
7501133e27eSPeter Avalos * Edit the last file in the command line (ifile) list.
7511133e27eSPeter Avalos */
edit_last(void)752*320d7c8aSAaron LI public int edit_last(void)
7531133e27eSPeter Avalos {
7541133e27eSPeter Avalos curr_ifile = NULL_IFILE;
7551133e27eSPeter Avalos return (edit_prev(1));
7561133e27eSPeter Avalos }
7571133e27eSPeter Avalos
7581133e27eSPeter Avalos
7591133e27eSPeter Avalos /*
7601133e27eSPeter Avalos * Edit the n-th next or previous file in the command line (ifile) list.
7611133e27eSPeter Avalos */
edit_istep(IFILE h,int n,int dir)762*320d7c8aSAaron LI static int edit_istep(IFILE h, int n, int dir)
7631133e27eSPeter Avalos {
7641133e27eSPeter Avalos IFILE next;
7651133e27eSPeter Avalos
7661133e27eSPeter Avalos /*
7671133e27eSPeter Avalos * Skip n filenames, then try to edit each filename.
7681133e27eSPeter Avalos */
7691133e27eSPeter Avalos for (;;)
7701133e27eSPeter Avalos {
7711133e27eSPeter Avalos next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
7721133e27eSPeter Avalos if (--n < 0)
7731133e27eSPeter Avalos {
7741133e27eSPeter Avalos if (edit_ifile(h) == 0)
7751133e27eSPeter Avalos break;
7761133e27eSPeter Avalos }
7771133e27eSPeter Avalos if (next == NULL_IFILE)
7781133e27eSPeter Avalos {
7791133e27eSPeter Avalos /*
7801133e27eSPeter Avalos * Reached end of the ifile list.
7811133e27eSPeter Avalos */
7821133e27eSPeter Avalos return (1);
7831133e27eSPeter Avalos }
7841133e27eSPeter Avalos if (ABORT_SIGS())
7851133e27eSPeter Avalos {
7861133e27eSPeter Avalos /*
7871133e27eSPeter Avalos * Interrupt breaks out, if we're in a long
7881133e27eSPeter Avalos * list of files that can't be opened.
7891133e27eSPeter Avalos */
7901133e27eSPeter Avalos return (1);
7911133e27eSPeter Avalos }
7921133e27eSPeter Avalos h = next;
7931133e27eSPeter Avalos }
7941133e27eSPeter Avalos /*
7951133e27eSPeter Avalos * Found a file that we can edit.
7961133e27eSPeter Avalos */
7971133e27eSPeter Avalos return (0);
7981133e27eSPeter Avalos }
7991133e27eSPeter Avalos
edit_inext(IFILE h,int n)800*320d7c8aSAaron LI static int edit_inext(IFILE h, int n)
8011133e27eSPeter Avalos {
8021133e27eSPeter Avalos return (edit_istep(h, n, +1));
8031133e27eSPeter Avalos }
8041133e27eSPeter Avalos
edit_next(int n)805*320d7c8aSAaron LI public int edit_next(int n)
8061133e27eSPeter Avalos {
8071133e27eSPeter Avalos return edit_istep(curr_ifile, n, +1);
8081133e27eSPeter Avalos }
8091133e27eSPeter Avalos
edit_iprev(IFILE h,int n)810*320d7c8aSAaron LI static int edit_iprev(IFILE h, int n)
8111133e27eSPeter Avalos {
8121133e27eSPeter Avalos return (edit_istep(h, n, -1));
8131133e27eSPeter Avalos }
8141133e27eSPeter Avalos
edit_prev(int n)815*320d7c8aSAaron LI public int edit_prev(int n)
8161133e27eSPeter Avalos {
8171133e27eSPeter Avalos return edit_istep(curr_ifile, n, -1);
8181133e27eSPeter Avalos }
8191133e27eSPeter Avalos
8201133e27eSPeter Avalos /*
8211133e27eSPeter Avalos * Edit a specific file in the command line (ifile) list.
8221133e27eSPeter Avalos */
edit_index(int n)823*320d7c8aSAaron LI public int edit_index(int n)
8241133e27eSPeter Avalos {
8251133e27eSPeter Avalos IFILE h;
8261133e27eSPeter Avalos
8271133e27eSPeter Avalos h = NULL_IFILE;
8281133e27eSPeter Avalos do
8291133e27eSPeter Avalos {
8301133e27eSPeter Avalos if ((h = next_ifile(h)) == NULL_IFILE)
8311133e27eSPeter Avalos {
8321133e27eSPeter Avalos /*
8331133e27eSPeter Avalos * Reached end of the list without finding it.
8341133e27eSPeter Avalos */
8351133e27eSPeter Avalos return (1);
8361133e27eSPeter Avalos }
8371133e27eSPeter Avalos } while (get_index(h) != n);
8381133e27eSPeter Avalos
8391133e27eSPeter Avalos return (edit_ifile(h));
8401133e27eSPeter Avalos }
8411133e27eSPeter Avalos
save_curr_ifile(void)842*320d7c8aSAaron LI public IFILE save_curr_ifile(void)
8431133e27eSPeter Avalos {
8441133e27eSPeter Avalos if (curr_ifile != NULL_IFILE)
8451133e27eSPeter Avalos hold_ifile(curr_ifile, 1);
8461133e27eSPeter Avalos return (curr_ifile);
8471133e27eSPeter Avalos }
8481133e27eSPeter Avalos
unsave_ifile(IFILE save_ifile)849*320d7c8aSAaron LI public void unsave_ifile(IFILE save_ifile)
8501133e27eSPeter Avalos {
8511133e27eSPeter Avalos if (save_ifile != NULL_IFILE)
8521133e27eSPeter Avalos hold_ifile(save_ifile, -1);
8531133e27eSPeter Avalos }
8541133e27eSPeter Avalos
8551133e27eSPeter Avalos /*
8561133e27eSPeter Avalos * Reedit the ifile which was previously open.
8571133e27eSPeter Avalos */
reedit_ifile(IFILE save_ifile)858*320d7c8aSAaron LI public void reedit_ifile(IFILE save_ifile)
8591133e27eSPeter Avalos {
8601133e27eSPeter Avalos IFILE next;
8611133e27eSPeter Avalos IFILE prev;
8621133e27eSPeter Avalos
8631133e27eSPeter Avalos /*
8641133e27eSPeter Avalos * Try to reopen the ifile.
8651133e27eSPeter Avalos * Note that opening it may fail (maybe the file was removed),
8661133e27eSPeter Avalos * in which case the ifile will be deleted from the list.
8671133e27eSPeter Avalos * So save the next and prev ifiles first.
8681133e27eSPeter Avalos */
8691133e27eSPeter Avalos unsave_ifile(save_ifile);
8701133e27eSPeter Avalos next = next_ifile(save_ifile);
8711133e27eSPeter Avalos prev = prev_ifile(save_ifile);
8721133e27eSPeter Avalos if (edit_ifile(save_ifile) == 0)
8731133e27eSPeter Avalos return;
8741133e27eSPeter Avalos /*
8751133e27eSPeter Avalos * If can't reopen it, open the next input file in the list.
8761133e27eSPeter Avalos */
8771133e27eSPeter Avalos if (next != NULL_IFILE && edit_inext(next, 0) == 0)
8781133e27eSPeter Avalos return;
8791133e27eSPeter Avalos /*
8801133e27eSPeter Avalos * If can't open THAT one, open the previous input file in the list.
8811133e27eSPeter Avalos */
8821133e27eSPeter Avalos if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
8831133e27eSPeter Avalos return;
8841133e27eSPeter Avalos /*
8851133e27eSPeter Avalos * If can't even open that, we're stuck. Just quit.
8861133e27eSPeter Avalos */
8871133e27eSPeter Avalos quit(QUIT_ERROR);
8881133e27eSPeter Avalos }
8891133e27eSPeter Avalos
reopen_curr_ifile(void)890*320d7c8aSAaron LI public void reopen_curr_ifile(void)
8911133e27eSPeter Avalos {
8921133e27eSPeter Avalos IFILE save_ifile = save_curr_ifile();
8931133e27eSPeter Avalos close_file();
8941133e27eSPeter Avalos reedit_ifile(save_ifile);
8951133e27eSPeter Avalos }
8961133e27eSPeter Avalos
8971133e27eSPeter Avalos /*
8981133e27eSPeter Avalos * Edit standard input.
8991133e27eSPeter Avalos */
edit_stdin(void)900*320d7c8aSAaron LI public int edit_stdin(void)
9011133e27eSPeter Avalos {
9021133e27eSPeter Avalos if (isatty(fd0))
9031133e27eSPeter Avalos {
9041133e27eSPeter Avalos error("Missing filename (\"less --help\" for help)", NULL_PARG);
9051133e27eSPeter Avalos quit(QUIT_OK);
9061133e27eSPeter Avalos }
9071133e27eSPeter Avalos return (edit("-"));
9081133e27eSPeter Avalos }
9091133e27eSPeter Avalos
9101133e27eSPeter Avalos /*
9111133e27eSPeter Avalos * Copy a file directly to standard output.
9121133e27eSPeter Avalos * Used if standard output is not a tty.
9131133e27eSPeter Avalos */
cat_file(void)914*320d7c8aSAaron LI public void cat_file(void)
9151133e27eSPeter Avalos {
91602d62a0fSDaniel Fojt int c;
9171133e27eSPeter Avalos
9181133e27eSPeter Avalos while ((c = ch_forw_get()) != EOI)
9191133e27eSPeter Avalos putchr(c);
9201133e27eSPeter Avalos flush();
9211133e27eSPeter Avalos }
9221133e27eSPeter Avalos
9231133e27eSPeter Avalos #if LOGFILE
9241133e27eSPeter Avalos
9250c7ad07eSAntonio Huete Jimenez #define OVERWRITE_OPTIONS "Overwrite, Append, Don't log, or Quit?"
9260c7ad07eSAntonio Huete Jimenez
9271133e27eSPeter Avalos /*
9281133e27eSPeter Avalos * If the user asked for a log file and our input file
9291133e27eSPeter Avalos * is standard input, create the log file.
9301133e27eSPeter Avalos * We take care not to blindly overwrite an existing file.
9311133e27eSPeter Avalos */
use_logfile(char * filename)932*320d7c8aSAaron LI public void use_logfile(char *filename)
9331133e27eSPeter Avalos {
93402d62a0fSDaniel Fojt int exists;
93502d62a0fSDaniel Fojt int answer;
9361133e27eSPeter Avalos PARG parg;
9371133e27eSPeter Avalos
9381133e27eSPeter Avalos if (ch_getflags() & CH_CANSEEK)
9391133e27eSPeter Avalos /*
9401133e27eSPeter Avalos * Can't currently use a log file on a file that can seek.
9411133e27eSPeter Avalos */
9421133e27eSPeter Avalos return;
9431133e27eSPeter Avalos
9441133e27eSPeter Avalos /*
9451133e27eSPeter Avalos * {{ We could use access() here. }}
9461133e27eSPeter Avalos */
9471133e27eSPeter Avalos exists = open(filename, OPEN_READ);
948fa0be7c5SJohn Marino if (exists >= 0)
9491133e27eSPeter Avalos close(exists);
9501133e27eSPeter Avalos exists = (exists >= 0);
9511133e27eSPeter Avalos
9521133e27eSPeter Avalos /*
9531133e27eSPeter Avalos * Decide whether to overwrite the log file or append to it.
9541133e27eSPeter Avalos * If it doesn't exist we "overwrite" it.
9551133e27eSPeter Avalos */
9561133e27eSPeter Avalos if (!exists || force_logfile)
9571133e27eSPeter Avalos {
9581133e27eSPeter Avalos /*
9591133e27eSPeter Avalos * Overwrite (or create) the log file.
9601133e27eSPeter Avalos */
9611133e27eSPeter Avalos answer = 'O';
9621133e27eSPeter Avalos } else
9631133e27eSPeter Avalos {
9641133e27eSPeter Avalos /*
9651133e27eSPeter Avalos * Ask user what to do.
9661133e27eSPeter Avalos */
9671133e27eSPeter Avalos parg.p_string = filename;
9680c7ad07eSAntonio Huete Jimenez answer = query("Warning: \"%s\" exists; "OVERWRITE_OPTIONS" ", &parg);
9691133e27eSPeter Avalos }
9701133e27eSPeter Avalos
9711133e27eSPeter Avalos loop:
9721133e27eSPeter Avalos switch (answer)
9731133e27eSPeter Avalos {
9741133e27eSPeter Avalos case 'O': case 'o':
9751133e27eSPeter Avalos /*
9761133e27eSPeter Avalos * Overwrite: create the file.
9771133e27eSPeter Avalos */
978*320d7c8aSAaron LI logfile = creat(filename, CREAT_RW);
9791133e27eSPeter Avalos break;
9801133e27eSPeter Avalos case 'A': case 'a':
9811133e27eSPeter Avalos /*
9821133e27eSPeter Avalos * Append: open the file and seek to the end.
9831133e27eSPeter Avalos */
9841133e27eSPeter Avalos logfile = open(filename, OPEN_APPEND);
9851133e27eSPeter Avalos if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK)
9861133e27eSPeter Avalos {
9871133e27eSPeter Avalos close(logfile);
9881133e27eSPeter Avalos logfile = -1;
9891133e27eSPeter Avalos }
9901133e27eSPeter Avalos break;
9911133e27eSPeter Avalos case 'D': case 'd':
9921133e27eSPeter Avalos /*
9931133e27eSPeter Avalos * Don't do anything.
9941133e27eSPeter Avalos */
9951133e27eSPeter Avalos return;
9961133e27eSPeter Avalos default:
9971133e27eSPeter Avalos /*
9981133e27eSPeter Avalos * Eh?
9991133e27eSPeter Avalos */
10000c7ad07eSAntonio Huete Jimenez
10010c7ad07eSAntonio Huete Jimenez answer = query(OVERWRITE_OPTIONS" (Type \"O\", \"A\", \"D\" or \"Q\") ", NULL_PARG);
10021133e27eSPeter Avalos goto loop;
10031133e27eSPeter Avalos }
10041133e27eSPeter Avalos
10051133e27eSPeter Avalos if (logfile < 0)
10061133e27eSPeter Avalos {
10071133e27eSPeter Avalos /*
10081133e27eSPeter Avalos * Error in opening logfile.
10091133e27eSPeter Avalos */
10101133e27eSPeter Avalos parg.p_string = filename;
10111133e27eSPeter Avalos error("Cannot write to \"%s\"", &parg);
10121133e27eSPeter Avalos return;
10131133e27eSPeter Avalos }
10141133e27eSPeter Avalos SET_BINARY(logfile);
10151133e27eSPeter Avalos }
10161133e27eSPeter Avalos
10171133e27eSPeter Avalos #endif
1018