1a5f0fb15SPaul Saab /*
2d713e089SXin LI * Copyright (C) 1984-2023 Mark Nudelman
3a5f0fb15SPaul Saab *
4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public
5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file.
6a5f0fb15SPaul Saab *
796e55cc7SXin LI * For more information, see the README file.
8a5f0fb15SPaul Saab */
9a5f0fb15SPaul Saab
10a5f0fb15SPaul Saab
11a5f0fb15SPaul Saab #include "less.h"
12b2ea2440SXin LI #include "position.h"
13464501a8SXin LI #if HAVE_STAT
14464501a8SXin LI #include <sys/stat.h>
15464501a8SXin LI #endif
16d713e089SXin LI #if HAVE_SYS_WAIT_H
17d713e089SXin LI #include <sys/wait.h>
18b2ea2440SXin LI #endif
19d713e089SXin LI #include <signal.h>
20a5f0fb15SPaul Saab
21a5f0fb15SPaul Saab public int fd0 = 0;
22a5f0fb15SPaul Saab
23a5f0fb15SPaul Saab extern int new_file;
24a5f0fb15SPaul Saab extern int cbufs;
25a5f0fb15SPaul Saab extern char *every_first_cmd;
26a5f0fb15SPaul Saab extern int force_open;
27a5f0fb15SPaul Saab extern int is_tty;
28a5f0fb15SPaul Saab extern int sigs;
292235c7feSXin LI extern int hshift;
3030a1828cSXin LI extern int want_filesize;
3195270f73SXin LI extern int consecutive_nulls;
32d713e089SXin LI extern int modelines;
33d713e089SXin LI extern int show_preproc_error;
34a5f0fb15SPaul Saab extern IFILE curr_ifile;
35a5f0fb15SPaul Saab extern IFILE old_ifile;
36a5f0fb15SPaul Saab extern struct scrpos initial_scrpos;
37f6b74a7dSXin LI extern void *ml_examine;
38a5f0fb15SPaul Saab #if SPACES_IN_FILENAMES
39a5f0fb15SPaul Saab extern char openquote;
40a5f0fb15SPaul Saab extern char closequote;
41a5f0fb15SPaul Saab #endif
42a5f0fb15SPaul Saab
43a5f0fb15SPaul Saab #if LOGFILE
44a5f0fb15SPaul Saab extern int logfile;
45a5f0fb15SPaul Saab extern int force_logfile;
46a5f0fb15SPaul Saab extern char *namelogfile;
47a5f0fb15SPaul Saab #endif
48a5f0fb15SPaul Saab
49464501a8SXin LI #if HAVE_STAT_INO
50464501a8SXin LI public dev_t curr_dev;
51464501a8SXin LI public ino_t curr_ino;
52464501a8SXin LI #endif
53464501a8SXin LI
54a5f0fb15SPaul Saab /*
55a5f0fb15SPaul Saab * Textlist functions deal with a list of words separated by spaces.
56a5f0fb15SPaul Saab * init_textlist sets up a textlist structure.
57a5f0fb15SPaul Saab * forw_textlist uses that structure to iterate thru the list of
58a5f0fb15SPaul Saab * words, returning each one as a standard null-terminated string.
59a5f0fb15SPaul Saab * back_textlist does the same, but runs thru the list backwards.
60a5f0fb15SPaul Saab */
init_textlist(struct textlist * tlist,char * str)61d713e089SXin LI public void init_textlist(struct textlist *tlist, char *str)
62a5f0fb15SPaul Saab {
63a5f0fb15SPaul Saab char *s;
64a5f0fb15SPaul Saab #if SPACES_IN_FILENAMES
65000ba3e8STim J. Robbins int meta_quoted = 0;
66000ba3e8STim J. Robbins int delim_quoted = 0;
67000ba3e8STim J. Robbins char *esc = get_meta_escape();
68a15691bfSXin LI int esclen = (int) strlen(esc);
69a5f0fb15SPaul Saab #endif
70a5f0fb15SPaul Saab
71a5f0fb15SPaul Saab tlist->string = skipsp(str);
72a5f0fb15SPaul Saab tlist->endstring = tlist->string + strlen(tlist->string);
73a5f0fb15SPaul Saab for (s = str; s < tlist->endstring; s++)
74a5f0fb15SPaul Saab {
75a5f0fb15SPaul Saab #if SPACES_IN_FILENAMES
76000ba3e8STim J. Robbins if (meta_quoted)
77000ba3e8STim J. Robbins {
78000ba3e8STim J. Robbins meta_quoted = 0;
79000ba3e8STim J. Robbins } else if (esclen > 0 && s + esclen < tlist->endstring &&
80000ba3e8STim J. Robbins strncmp(s, esc, esclen) == 0)
81000ba3e8STim J. Robbins {
82000ba3e8STim J. Robbins meta_quoted = 1;
83000ba3e8STim J. Robbins s += esclen - 1;
84000ba3e8STim J. Robbins } else if (delim_quoted)
85000ba3e8STim J. Robbins {
86000ba3e8STim J. Robbins if (*s == closequote)
87000ba3e8STim J. Robbins delim_quoted = 0;
88000ba3e8STim J. Robbins } else /* (!delim_quoted) */
89000ba3e8STim J. Robbins {
90000ba3e8STim J. Robbins if (*s == openquote)
91000ba3e8STim J. Robbins delim_quoted = 1;
92000ba3e8STim J. Robbins else if (*s == ' ')
93a5f0fb15SPaul Saab *s = '\0';
94000ba3e8STim J. Robbins }
95a5f0fb15SPaul Saab #else
96a5f0fb15SPaul Saab if (*s == ' ')
97a5f0fb15SPaul Saab *s = '\0';
98a5f0fb15SPaul Saab #endif
99a5f0fb15SPaul Saab }
100a5f0fb15SPaul Saab }
101a5f0fb15SPaul Saab
forw_textlist(struct textlist * tlist,char * prev)102d713e089SXin LI public char * forw_textlist(struct textlist *tlist, char *prev)
103a5f0fb15SPaul Saab {
104a5f0fb15SPaul Saab char *s;
105a5f0fb15SPaul Saab
106a5f0fb15SPaul Saab /*
107a5f0fb15SPaul Saab * prev == NULL means return the first word in the list.
108a5f0fb15SPaul Saab * Otherwise, return the word after "prev".
109a5f0fb15SPaul Saab */
110a5f0fb15SPaul Saab if (prev == NULL)
111a5f0fb15SPaul Saab s = tlist->string;
112a5f0fb15SPaul Saab else
113a5f0fb15SPaul Saab s = prev + strlen(prev);
114a5f0fb15SPaul Saab if (s >= tlist->endstring)
115a5f0fb15SPaul Saab return (NULL);
116a5f0fb15SPaul Saab while (*s == '\0')
117a5f0fb15SPaul Saab s++;
118a5f0fb15SPaul Saab if (s >= tlist->endstring)
119a5f0fb15SPaul Saab return (NULL);
120a5f0fb15SPaul Saab return (s);
121a5f0fb15SPaul Saab }
122a5f0fb15SPaul Saab
back_textlist(struct textlist * tlist,char * prev)123d713e089SXin LI public char * back_textlist(struct textlist *tlist, char *prev)
124a5f0fb15SPaul Saab {
125a5f0fb15SPaul Saab char *s;
126a5f0fb15SPaul Saab
127a5f0fb15SPaul Saab /*
128a5f0fb15SPaul Saab * prev == NULL means return the last word in the list.
129a5f0fb15SPaul Saab * Otherwise, return the word before "prev".
130a5f0fb15SPaul Saab */
131a5f0fb15SPaul Saab if (prev == NULL)
132a5f0fb15SPaul Saab s = tlist->endstring;
133a5f0fb15SPaul Saab else if (prev <= tlist->string)
134a5f0fb15SPaul Saab return (NULL);
135a5f0fb15SPaul Saab else
136a5f0fb15SPaul Saab s = prev - 1;
137a5f0fb15SPaul Saab while (*s == '\0')
138a5f0fb15SPaul Saab s--;
139a5f0fb15SPaul Saab if (s <= tlist->string)
140a5f0fb15SPaul Saab return (NULL);
141a5f0fb15SPaul Saab while (s[-1] != '\0' && s > tlist->string)
142a5f0fb15SPaul Saab s--;
143a5f0fb15SPaul Saab return (s);
144a5f0fb15SPaul Saab }
145a5f0fb15SPaul Saab
146a5f0fb15SPaul Saab /*
147d713e089SXin LI * Parse a single option setting in a modeline.
148d713e089SXin LI */
modeline_option(char * str,int opt_len)149d713e089SXin LI static void modeline_option(char *str, int opt_len)
150d713e089SXin LI {
151d713e089SXin LI struct mloption { char *opt_name; void (*opt_func)(char*,int); };
152d713e089SXin LI struct mloption options[] = {
153d713e089SXin LI { "ts=", set_tabs },
154d713e089SXin LI { "tabstop=", set_tabs },
155d713e089SXin LI { NULL, NULL }
156d713e089SXin LI };
157d713e089SXin LI struct mloption *opt;
158d713e089SXin LI for (opt = options; opt->opt_name != NULL; opt++)
159d713e089SXin LI {
160d713e089SXin LI int name_len = strlen(opt->opt_name);
161d713e089SXin LI if (opt_len > name_len && strncmp(str, opt->opt_name, name_len) == 0)
162d713e089SXin LI {
163d713e089SXin LI (*opt->opt_func)(str + name_len, opt_len - name_len);
164d713e089SXin LI break;
165d713e089SXin LI }
166d713e089SXin LI }
167d713e089SXin LI }
168d713e089SXin LI
169d713e089SXin LI /*
170d713e089SXin LI * String length, terminated by option separator (space or colon).
171d713e089SXin LI * Space/colon can be escaped with backspace.
172d713e089SXin LI */
modeline_option_len(char * str)173d713e089SXin LI static int modeline_option_len(char *str)
174d713e089SXin LI {
175d713e089SXin LI int esc = FALSE;
176d713e089SXin LI char *s;
177d713e089SXin LI for (s = str; *s != '\0'; s++)
178d713e089SXin LI {
179d713e089SXin LI if (esc)
180d713e089SXin LI esc = FALSE;
181d713e089SXin LI else if (*s == '\\')
182d713e089SXin LI esc = TRUE;
183d713e089SXin LI else if (*s == ' ' || *s == ':') /* separator */
184d713e089SXin LI break;
185d713e089SXin LI }
186d713e089SXin LI return (s - str);
187d713e089SXin LI }
188d713e089SXin LI
189d713e089SXin LI /*
190d713e089SXin LI * Parse colon- or space-separated option settings in a modeline.
191d713e089SXin LI */
modeline_options(char * str,char end_char)192d713e089SXin LI static void modeline_options(char *str, char end_char)
193d713e089SXin LI {
194d713e089SXin LI for (;;)
195d713e089SXin LI {
196d713e089SXin LI int opt_len;
197d713e089SXin LI str = skipsp(str);
198d713e089SXin LI if (*str == '\0' || *str == end_char)
199d713e089SXin LI break;
200d713e089SXin LI opt_len = modeline_option_len(str);
201d713e089SXin LI modeline_option(str, opt_len);
202d713e089SXin LI str += opt_len;
203d713e089SXin LI if (*str != '\0')
204d713e089SXin LI str += 1; /* skip past the separator */
205d713e089SXin LI }
206d713e089SXin LI }
207d713e089SXin LI
208d713e089SXin LI /*
209d713e089SXin LI * See if there is a modeline string in a line.
210d713e089SXin LI */
check_modeline(char * line)211d713e089SXin LI static void check_modeline(char *line)
212d713e089SXin LI {
213d713e089SXin LI #if HAVE_STRSTR
214d713e089SXin LI static char *pgms[] = { "less:", "vim:", "vi:", "ex:", NULL };
215d713e089SXin LI char **pgm;
216d713e089SXin LI for (pgm = pgms; *pgm != NULL; ++pgm)
217d713e089SXin LI {
218d713e089SXin LI char *pline = line;
219d713e089SXin LI for (;;)
220d713e089SXin LI {
221d713e089SXin LI char *str;
222d713e089SXin LI pline = strstr(pline, *pgm);
223d713e089SXin LI if (pline == NULL) /* pgm is not in this line */
224d713e089SXin LI break;
225d713e089SXin LI str = skipsp(pline + strlen(*pgm));
226d713e089SXin LI if (pline == line || pline[-1] == ' ')
227d713e089SXin LI {
228d713e089SXin LI if (strncmp(str, "set ", 4) == 0)
229d713e089SXin LI modeline_options(str+4, ':');
230d713e089SXin LI else if (pgm != &pgms[0]) /* "less:" requires "set" */
231d713e089SXin LI modeline_options(str, '\0');
232d713e089SXin LI break;
233d713e089SXin LI }
234d713e089SXin LI /* Continue searching the rest of the line. */
235d713e089SXin LI pline = str;
236d713e089SXin LI }
237d713e089SXin LI }
238d713e089SXin LI #endif /* HAVE_STRSTR */
239d713e089SXin LI }
240d713e089SXin LI
241d713e089SXin LI /*
242d713e089SXin LI * Read lines from start of file and check if any are modelines.
243d713e089SXin LI */
check_modelines(void)244d713e089SXin LI static void check_modelines(void)
245d713e089SXin LI {
246d713e089SXin LI POSITION pos = ch_zero();
247d713e089SXin LI int i;
248d713e089SXin LI for (i = 0; i < modelines; i++)
249d713e089SXin LI {
250d713e089SXin LI char *line;
251d713e089SXin LI int line_len;
252d713e089SXin LI if (ABORT_SIGS())
253d713e089SXin LI return;
254d713e089SXin LI pos = forw_raw_line(pos, &line, &line_len);
255d713e089SXin LI if (pos == NULL_POSITION)
256d713e089SXin LI break;
257d713e089SXin LI check_modeline(line);
258d713e089SXin LI }
259d713e089SXin LI }
260d713e089SXin LI
261d713e089SXin LI /*
262b2ea2440SXin LI * Close a pipe opened via popen.
263b2ea2440SXin LI */
close_pipe(FILE * pipefd)264d713e089SXin LI static void close_pipe(FILE *pipefd)
265b2ea2440SXin LI {
266d713e089SXin LI int status;
267d713e089SXin LI PARG parg;
268d713e089SXin LI
269b2ea2440SXin LI if (pipefd == NULL)
270b2ea2440SXin LI return;
271b2ea2440SXin LI #if OS2
272b2ea2440SXin LI /*
273b2ea2440SXin LI * The pclose function of OS/2 emx sometimes fails.
274b2ea2440SXin LI * Send SIGINT to the piped process before closing it.
275b2ea2440SXin LI */
276b2ea2440SXin LI kill(pipefd->_pid, SIGINT);
277b2ea2440SXin LI #endif
278d713e089SXin LI status = pclose(pipefd);
279d713e089SXin LI if (status == -1)
280d713e089SXin LI {
281d713e089SXin LI /* An internal error in 'less', not a preprocessor error. */
282d713e089SXin LI parg.p_string = errno_message("pclose");
283d713e089SXin LI error("%s", &parg);
284d713e089SXin LI free(parg.p_string);
285d713e089SXin LI return;
286d713e089SXin LI }
287d713e089SXin LI if (!show_preproc_error)
288d713e089SXin LI return;
289d713e089SXin LI #if defined WIFEXITED && defined WEXITSTATUS
290d713e089SXin LI if (WIFEXITED(status))
291d713e089SXin LI {
292d713e089SXin LI int s = WEXITSTATUS(status);
293d713e089SXin LI if (s != 0)
294d713e089SXin LI {
295d713e089SXin LI parg.p_int = s;
296d713e089SXin LI error("Input preprocessor failed (status %d)", &parg);
297d713e089SXin LI }
298d713e089SXin LI return;
299d713e089SXin LI }
300d713e089SXin LI #endif
301d713e089SXin LI #if defined WIFSIGNALED && defined WTERMSIG && HAVE_STRSIGNAL
302d713e089SXin LI if (WIFSIGNALED(status))
303d713e089SXin LI {
304d713e089SXin LI int sig = WTERMSIG(status);
305d713e089SXin LI if (sig != SIGPIPE || ch_length() != NULL_POSITION)
306d713e089SXin LI {
307d713e089SXin LI parg.p_string = signal_message(sig);
308d713e089SXin LI error("Input preprocessor terminated: %s", &parg);
309d713e089SXin LI }
310d713e089SXin LI return;
311d713e089SXin LI }
312d713e089SXin LI #endif
313d713e089SXin LI if (status != 0)
314d713e089SXin LI {
315d713e089SXin LI parg.p_int = status;
316d713e089SXin LI error("Input preprocessor exited with status %x", &parg);
317d713e089SXin LI }
318d713e089SXin LI }
319d713e089SXin LI
320d713e089SXin LI /*
321d713e089SXin LI * Drain and close an input pipe if needed.
322d713e089SXin LI */
close_altpipe(IFILE ifile)323d713e089SXin LI public void close_altpipe(IFILE ifile)
324d713e089SXin LI {
325d713e089SXin LI FILE *altpipe = get_altpipe(ifile);
326d713e089SXin LI if (altpipe != NULL && !(ch_getflags() & CH_KEEPOPEN))
327d713e089SXin LI {
328d713e089SXin LI close_pipe(altpipe);
329d713e089SXin LI set_altpipe(ifile, NULL);
330d713e089SXin LI }
331d713e089SXin LI }
332d713e089SXin LI
333d713e089SXin LI /*
334d713e089SXin LI * Check for error status from the current altpipe.
335d713e089SXin LI * May or may not close the pipe.
336d713e089SXin LI */
check_altpipe_error(void)337d713e089SXin LI public void check_altpipe_error(void)
338d713e089SXin LI {
339d713e089SXin LI if (!show_preproc_error)
340d713e089SXin LI return;
341d713e089SXin LI if (curr_ifile != NULL_IFILE && get_altfilename(curr_ifile) != NULL)
342d713e089SXin LI close_altpipe(curr_ifile);
343b2ea2440SXin LI }
344b2ea2440SXin LI
345b2ea2440SXin LI /*
346a5f0fb15SPaul Saab * Close the current input file.
347a5f0fb15SPaul Saab */
close_file(void)348d713e089SXin LI static void close_file(void)
349a5f0fb15SPaul Saab {
350a5f0fb15SPaul Saab struct scrpos scrpos;
351b2ea2440SXin LI char *altfilename;
352a5f0fb15SPaul Saab
353a5f0fb15SPaul Saab if (curr_ifile == NULL_IFILE)
354a5f0fb15SPaul Saab return;
355a5f0fb15SPaul Saab
356a5f0fb15SPaul Saab /*
357a5f0fb15SPaul Saab * Save the current position so that we can return to
358a5f0fb15SPaul Saab * the same position if we edit this file again.
359a5f0fb15SPaul Saab */
360b2ea2440SXin LI get_scrpos(&scrpos, TOP);
361a5f0fb15SPaul Saab if (scrpos.pos != NULL_POSITION)
362a5f0fb15SPaul Saab {
363a5f0fb15SPaul Saab store_pos(curr_ifile, &scrpos);
364a5f0fb15SPaul Saab lastmark();
365a5f0fb15SPaul Saab }
366a5f0fb15SPaul Saab /*
367a5f0fb15SPaul Saab * Close the file descriptor, unless it is a pipe.
368a5f0fb15SPaul Saab */
369a5f0fb15SPaul Saab ch_close();
370a5f0fb15SPaul Saab /*
371a5f0fb15SPaul Saab * If we opened a file using an alternate name,
372a5f0fb15SPaul Saab * do special stuff to close it.
373a5f0fb15SPaul Saab */
374b2ea2440SXin LI altfilename = get_altfilename(curr_ifile);
375b2ea2440SXin LI if (altfilename != NULL)
376a5f0fb15SPaul Saab {
377d713e089SXin LI close_altpipe(curr_ifile);
378b2ea2440SXin LI close_altfile(altfilename, get_filename(curr_ifile));
379b2ea2440SXin LI set_altfilename(curr_ifile, NULL);
380a5f0fb15SPaul Saab }
381a5f0fb15SPaul Saab curr_ifile = NULL_IFILE;
382464501a8SXin LI #if HAVE_STAT_INO
383464501a8SXin LI curr_ino = curr_dev = 0;
384464501a8SXin LI #endif
385a5f0fb15SPaul Saab }
386a5f0fb15SPaul Saab
387a5f0fb15SPaul Saab /*
388a5f0fb15SPaul Saab * Edit a new file (given its name).
389a5f0fb15SPaul Saab * Filename == "-" means standard input.
390a5f0fb15SPaul Saab * Filename == NULL means just close the current file.
391a5f0fb15SPaul Saab */
edit(char * filename)392d713e089SXin LI public int edit(char *filename)
393a5f0fb15SPaul Saab {
394a5f0fb15SPaul Saab if (filename == NULL)
395a5f0fb15SPaul Saab return (edit_ifile(NULL_IFILE));
396a5f0fb15SPaul Saab return (edit_ifile(get_ifile(filename, curr_ifile)));
397a5f0fb15SPaul Saab }
398a5f0fb15SPaul Saab
399a5f0fb15SPaul Saab /*
400d713e089SXin LI * Clean up what edit_ifile did before error return.
401d713e089SXin LI */
edit_error(char * filename,char * alt_filename,void * altpipe,IFILE ifile,IFILE was_curr_ifile)402d713e089SXin LI static int edit_error(char *filename, char *alt_filename, void *altpipe, IFILE ifile, IFILE was_curr_ifile)
403d713e089SXin LI {
404d713e089SXin LI if (alt_filename != NULL)
405d713e089SXin LI {
406d713e089SXin LI close_pipe(altpipe);
407d713e089SXin LI close_altfile(alt_filename, filename);
408d713e089SXin LI free(alt_filename);
409d713e089SXin LI }
410d713e089SXin LI del_ifile(ifile);
411d713e089SXin LI free(filename);
412d713e089SXin LI /*
413d713e089SXin LI * Re-open the current file.
414d713e089SXin LI */
415d713e089SXin LI if (was_curr_ifile == ifile)
416d713e089SXin LI {
417d713e089SXin LI /*
418d713e089SXin LI * Whoops. The "current" ifile is the one we just deleted.
419d713e089SXin LI * Just give up.
420d713e089SXin LI */
421d713e089SXin LI quit(QUIT_ERROR);
422d713e089SXin LI }
423d713e089SXin LI reedit_ifile(was_curr_ifile);
424d713e089SXin LI return (1);
425d713e089SXin LI }
426d713e089SXin LI
427d713e089SXin LI /*
428a5f0fb15SPaul Saab * Edit a new file (given its IFILE).
429a5f0fb15SPaul Saab * ifile == NULL means just close the current file.
430a5f0fb15SPaul Saab */
edit_ifile(IFILE ifile)431d713e089SXin LI public int edit_ifile(IFILE ifile)
432a5f0fb15SPaul Saab {
433a5f0fb15SPaul Saab int f;
434a5f0fb15SPaul Saab int answer;
435a5f0fb15SPaul Saab int chflags;
436a5f0fb15SPaul Saab char *filename;
437a5f0fb15SPaul Saab char *open_filename;
438a5f0fb15SPaul Saab char *alt_filename;
439b2ea2440SXin LI void *altpipe;
440a5f0fb15SPaul Saab IFILE was_curr_ifile;
441a5f0fb15SPaul Saab PARG parg;
442a5f0fb15SPaul Saab
443a5f0fb15SPaul Saab if (ifile == curr_ifile)
444a5f0fb15SPaul Saab {
445a5f0fb15SPaul Saab /*
446a5f0fb15SPaul Saab * Already have the correct file open.
447a5f0fb15SPaul Saab */
448a5f0fb15SPaul Saab return (0);
449a5f0fb15SPaul Saab }
450a5f0fb15SPaul Saab
451a5f0fb15SPaul Saab /*
452a5f0fb15SPaul Saab * We must close the currently open file now.
453a5f0fb15SPaul Saab * This is necessary to make the open_altfile/close_altfile pairs
454a5f0fb15SPaul Saab * nest properly (or rather to avoid nesting at all).
455a5f0fb15SPaul Saab * {{ Some stupid implementations of popen() mess up if you do:
456a5f0fb15SPaul Saab * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
457a5f0fb15SPaul Saab */
458a5f0fb15SPaul Saab #if LOGFILE
459a5f0fb15SPaul Saab end_logfile();
460a5f0fb15SPaul Saab #endif
461a5f0fb15SPaul Saab was_curr_ifile = save_curr_ifile();
462a5f0fb15SPaul Saab if (curr_ifile != NULL_IFILE)
463a5f0fb15SPaul Saab {
464a5f0fb15SPaul Saab chflags = ch_getflags();
465a5f0fb15SPaul Saab close_file();
466a5f0fb15SPaul Saab if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
467a5f0fb15SPaul Saab {
468a5f0fb15SPaul Saab /*
469a5f0fb15SPaul Saab * Don't keep the help file in the ifile list.
470a5f0fb15SPaul Saab */
471a5f0fb15SPaul Saab del_ifile(was_curr_ifile);
472a5f0fb15SPaul Saab was_curr_ifile = old_ifile;
473a5f0fb15SPaul Saab }
474a5f0fb15SPaul Saab }
475a5f0fb15SPaul Saab
476a5f0fb15SPaul Saab if (ifile == NULL_IFILE)
477a5f0fb15SPaul Saab {
478a5f0fb15SPaul Saab /*
479a5f0fb15SPaul Saab * No new file to open.
480a5f0fb15SPaul Saab * (Don't set old_ifile, because if you call edit_ifile(NULL),
481a5f0fb15SPaul Saab * you're supposed to have saved curr_ifile yourself,
482a5f0fb15SPaul Saab * and you'll restore it if necessary.)
483a5f0fb15SPaul Saab */
484a5f0fb15SPaul Saab unsave_ifile(was_curr_ifile);
485a5f0fb15SPaul Saab return (0);
486a5f0fb15SPaul Saab }
487a5f0fb15SPaul Saab
488000ba3e8STim J. Robbins filename = save(get_filename(ifile));
489b2ea2440SXin LI
490a5f0fb15SPaul Saab /*
491a5f0fb15SPaul Saab * See if LESSOPEN specifies an "alternate" file to open.
492a5f0fb15SPaul Saab */
493b2ea2440SXin LI altpipe = get_altpipe(ifile);
494b2ea2440SXin LI if (altpipe != NULL)
495b2ea2440SXin LI {
496b2ea2440SXin LI /*
497b2ea2440SXin LI * File is already open.
498b2ea2440SXin LI * chflags and f are not used by ch_init if ifile has
499b2ea2440SXin LI * filestate which should be the case if we're here.
500b2ea2440SXin LI * Set them here to avoid uninitialized variable warnings.
501b2ea2440SXin LI */
502b2ea2440SXin LI chflags = 0;
503b2ea2440SXin LI f = -1;
504b2ea2440SXin LI alt_filename = get_altfilename(ifile);
505a5f0fb15SPaul Saab open_filename = (alt_filename != NULL) ? alt_filename : filename;
506b2ea2440SXin LI } else
507b2ea2440SXin LI {
508b2ea2440SXin LI if (strcmp(filename, FAKE_HELPFILE) == 0 ||
509b2ea2440SXin LI strcmp(filename, FAKE_EMPTYFILE) == 0)
510b2ea2440SXin LI alt_filename = NULL;
511b2ea2440SXin LI else
512b2ea2440SXin LI alt_filename = open_altfile(filename, &f, &altpipe);
513b2ea2440SXin LI
514b2ea2440SXin LI open_filename = (alt_filename != NULL) ? alt_filename : filename;
515a5f0fb15SPaul Saab
516a5f0fb15SPaul Saab chflags = 0;
517b2ea2440SXin LI if (altpipe != NULL)
518a5f0fb15SPaul Saab {
519a5f0fb15SPaul Saab /*
520a5f0fb15SPaul Saab * The alternate "file" is actually a pipe.
521a5f0fb15SPaul Saab * f has already been set to the file descriptor of the pipe
522a5f0fb15SPaul Saab * in the call to open_altfile above.
523a5f0fb15SPaul Saab * Keep the file descriptor open because it was opened
524a5f0fb15SPaul Saab * via popen(), and pclose() wants to close it.
525a5f0fb15SPaul Saab */
526a5f0fb15SPaul Saab chflags |= CH_POPENED;
527b2ea2440SXin LI if (strcmp(filename, "-") == 0)
528b2ea2440SXin LI chflags |= CH_KEEPOPEN;
529b2ea2440SXin LI } else if (strcmp(filename, "-") == 0)
530a5f0fb15SPaul Saab {
531a5f0fb15SPaul Saab /*
532a5f0fb15SPaul Saab * Use standard input.
533a5f0fb15SPaul Saab * Keep the file descriptor open because we can't reopen it.
534a5f0fb15SPaul Saab */
535a5f0fb15SPaul Saab f = fd0;
536a5f0fb15SPaul Saab chflags |= CH_KEEPOPEN;
537a5f0fb15SPaul Saab /*
538a5f0fb15SPaul Saab * Must switch stdin to BINARY mode.
539a5f0fb15SPaul Saab */
540a5f0fb15SPaul Saab SET_BINARY(f);
541a5f0fb15SPaul Saab #if MSDOS_COMPILER==DJGPPC
542a5f0fb15SPaul Saab /*
543a5f0fb15SPaul Saab * Setting stdin to binary by default causes
544a5f0fb15SPaul Saab * Ctrl-C to not raise SIGINT. We must undo
545a5f0fb15SPaul Saab * that side-effect.
546a5f0fb15SPaul Saab */
547a5f0fb15SPaul Saab __djgpp_set_ctrl_c(1);
548a5f0fb15SPaul Saab #endif
54996e55cc7SXin LI } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
55096e55cc7SXin LI {
55196e55cc7SXin LI f = -1;
55296e55cc7SXin LI chflags |= CH_NODATA;
553a5f0fb15SPaul Saab } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
554a5f0fb15SPaul Saab {
555a5f0fb15SPaul Saab f = -1;
556a5f0fb15SPaul Saab chflags |= CH_HELPFILE;
557a5f0fb15SPaul Saab } else if ((parg.p_string = bad_file(open_filename)) != NULL)
558a5f0fb15SPaul Saab {
559a5f0fb15SPaul Saab /*
560a5f0fb15SPaul Saab * It looks like a bad file. Don't try to open it.
561a5f0fb15SPaul Saab */
562a5f0fb15SPaul Saab error("%s", &parg);
563a5f0fb15SPaul Saab free(parg.p_string);
564d713e089SXin LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
565b2ea2440SXin LI } else if ((f = open(open_filename, OPEN_READ)) < 0)
566a5f0fb15SPaul Saab {
567a5f0fb15SPaul Saab /*
568a5f0fb15SPaul Saab * Got an error trying to open it.
569a5f0fb15SPaul Saab */
570a5f0fb15SPaul Saab parg.p_string = errno_message(filename);
571a5f0fb15SPaul Saab error("%s", &parg);
572a5f0fb15SPaul Saab free(parg.p_string);
573d713e089SXin LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
574a5f0fb15SPaul Saab } else
575a5f0fb15SPaul Saab {
576a5f0fb15SPaul Saab chflags |= CH_CANSEEK;
577a5f0fb15SPaul Saab if (!force_open && !opened(ifile) && bin_file(f))
578a5f0fb15SPaul Saab {
579a5f0fb15SPaul Saab /*
580a5f0fb15SPaul Saab * Looks like a binary file.
581a5f0fb15SPaul Saab * Ask user if we should proceed.
582a5f0fb15SPaul Saab */
583a5f0fb15SPaul Saab parg.p_string = filename;
584a5f0fb15SPaul Saab answer = query("\"%s\" may be a binary file. See it anyway? ",
585a5f0fb15SPaul Saab &parg);
586a5f0fb15SPaul Saab if (answer != 'y' && answer != 'Y')
587a5f0fb15SPaul Saab {
588a5f0fb15SPaul Saab close(f);
589d713e089SXin LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
590a5f0fb15SPaul Saab }
591a5f0fb15SPaul Saab }
592a5f0fb15SPaul Saab }
593b2ea2440SXin LI }
594d713e089SXin LI if (!force_open && f >= 0 && isatty(f))
595d713e089SXin LI {
596d713e089SXin LI PARG parg;
597d713e089SXin LI parg.p_string = filename;
598d713e089SXin LI error("%s is a terminal (use -f to open it)", &parg);
599d713e089SXin LI return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
600d713e089SXin LI }
601a5f0fb15SPaul Saab
602a5f0fb15SPaul Saab /*
603a5f0fb15SPaul Saab * Get the new ifile.
604a5f0fb15SPaul Saab * Get the saved position for the file.
605a5f0fb15SPaul Saab */
606a5f0fb15SPaul Saab if (was_curr_ifile != NULL_IFILE)
607a5f0fb15SPaul Saab {
608a5f0fb15SPaul Saab old_ifile = was_curr_ifile;
609a5f0fb15SPaul Saab unsave_ifile(was_curr_ifile);
610a5f0fb15SPaul Saab }
611a5f0fb15SPaul Saab curr_ifile = ifile;
612b2ea2440SXin LI set_altfilename(curr_ifile, alt_filename);
613b2ea2440SXin LI set_altpipe(curr_ifile, altpipe);
614a5f0fb15SPaul Saab set_open(curr_ifile); /* File has been opened */
615a5f0fb15SPaul Saab get_pos(curr_ifile, &initial_scrpos);
616a5f0fb15SPaul Saab new_file = TRUE;
617a5f0fb15SPaul Saab ch_init(f, chflags);
61895270f73SXin LI consecutive_nulls = 0;
619d713e089SXin LI check_modelines();
620a5f0fb15SPaul Saab
621a5f0fb15SPaul Saab if (!(chflags & CH_HELPFILE))
622a5f0fb15SPaul Saab {
623a5f0fb15SPaul Saab #if LOGFILE
624a5f0fb15SPaul Saab if (namelogfile != NULL && is_tty)
625a5f0fb15SPaul Saab use_logfile(namelogfile);
626a5f0fb15SPaul Saab #endif
627464501a8SXin LI #if HAVE_STAT_INO
628464501a8SXin LI /* Remember the i-number and device of the opened file. */
629b2ea2440SXin LI if (strcmp(open_filename, "-") != 0)
630464501a8SXin LI {
631464501a8SXin LI struct stat statbuf;
632b2ea2440SXin LI int r = stat(open_filename, &statbuf);
633464501a8SXin LI if (r == 0)
634464501a8SXin LI {
635464501a8SXin LI curr_ino = statbuf.st_ino;
636464501a8SXin LI curr_dev = statbuf.st_dev;
637464501a8SXin LI }
638464501a8SXin LI }
639464501a8SXin LI #endif
640a5f0fb15SPaul Saab if (every_first_cmd != NULL)
641a15691bfSXin LI {
642a5f0fb15SPaul Saab ungetsc(every_first_cmd);
6432235c7feSXin LI ungetcc_back(CHAR_END_COMMAND);
644a5f0fb15SPaul Saab }
645a15691bfSXin LI }
646a5f0fb15SPaul Saab
647a5f0fb15SPaul Saab flush();
648a5f0fb15SPaul Saab
649a5f0fb15SPaul Saab if (is_tty)
650a5f0fb15SPaul Saab {
651a5f0fb15SPaul Saab /*
652a5f0fb15SPaul Saab * Output is to a real tty.
653a5f0fb15SPaul Saab */
654a5f0fb15SPaul Saab
655a5f0fb15SPaul Saab /*
656a5f0fb15SPaul Saab * Indicate there is nothing displayed yet.
657a5f0fb15SPaul Saab */
658a5f0fb15SPaul Saab pos_clear();
659a5f0fb15SPaul Saab clr_linenum();
660a5f0fb15SPaul Saab #if HILITE_SEARCH
661a5f0fb15SPaul Saab clr_hilite();
662a5f0fb15SPaul Saab #endif
6632235c7feSXin LI hshift = 0;
664a15691bfSXin LI if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE))
665b7780dbeSXin LI {
666b7780dbeSXin LI char *qfilename = shell_quote(filename);
667b7780dbeSXin LI cmd_addhist(ml_examine, qfilename, 1);
668b7780dbeSXin LI free(qfilename);
669b7780dbeSXin LI }
67030a1828cSXin LI if (want_filesize)
67130a1828cSXin LI scan_eof();
672a5f0fb15SPaul Saab }
673a5f0fb15SPaul Saab free(filename);
674a5f0fb15SPaul Saab return (0);
675a5f0fb15SPaul Saab }
676a5f0fb15SPaul Saab
677a5f0fb15SPaul Saab /*
678a5f0fb15SPaul Saab * Edit a space-separated list of files.
679a5f0fb15SPaul Saab * For each filename in the list, enter it into the ifile list.
680a5f0fb15SPaul Saab * Then edit the first one.
681a5f0fb15SPaul Saab */
edit_list(char * filelist)682d713e089SXin LI public int edit_list(char *filelist)
683a5f0fb15SPaul Saab {
684a5f0fb15SPaul Saab IFILE save_ifile;
685a5f0fb15SPaul Saab char *good_filename;
686a5f0fb15SPaul Saab char *filename;
687a5f0fb15SPaul Saab char *gfilelist;
688a5f0fb15SPaul Saab char *gfilename;
689b2ea2440SXin LI char *qfilename;
690a5f0fb15SPaul Saab struct textlist tl_files;
691a5f0fb15SPaul Saab struct textlist tl_gfiles;
692a5f0fb15SPaul Saab
693a5f0fb15SPaul Saab save_ifile = save_curr_ifile();
694a5f0fb15SPaul Saab good_filename = NULL;
695a5f0fb15SPaul Saab
696a5f0fb15SPaul Saab /*
697a5f0fb15SPaul Saab * Run thru each filename in the list.
698a5f0fb15SPaul Saab * Try to glob the filename.
699a5f0fb15SPaul Saab * If it doesn't expand, just try to open the filename.
700a5f0fb15SPaul Saab * If it does expand, try to open each name in that list.
701a5f0fb15SPaul Saab */
702a5f0fb15SPaul Saab init_textlist(&tl_files, filelist);
703a5f0fb15SPaul Saab filename = NULL;
704a5f0fb15SPaul Saab while ((filename = forw_textlist(&tl_files, filename)) != NULL)
705a5f0fb15SPaul Saab {
706a5f0fb15SPaul Saab gfilelist = lglob(filename);
707a5f0fb15SPaul Saab init_textlist(&tl_gfiles, gfilelist);
708a5f0fb15SPaul Saab gfilename = NULL;
709a5f0fb15SPaul Saab while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
710a5f0fb15SPaul Saab {
711b2ea2440SXin LI qfilename = shell_unquote(gfilename);
712b2ea2440SXin LI if (edit(qfilename) == 0 && good_filename == NULL)
713a5f0fb15SPaul Saab good_filename = get_filename(curr_ifile);
714b2ea2440SXin LI free(qfilename);
715a5f0fb15SPaul Saab }
716a5f0fb15SPaul Saab free(gfilelist);
717a5f0fb15SPaul Saab }
718a5f0fb15SPaul Saab /*
719a5f0fb15SPaul Saab * Edit the first valid filename in the list.
720a5f0fb15SPaul Saab */
721a5f0fb15SPaul Saab if (good_filename == NULL)
722a5f0fb15SPaul Saab {
723a5f0fb15SPaul Saab unsave_ifile(save_ifile);
724a5f0fb15SPaul Saab return (1);
725a5f0fb15SPaul Saab }
726a5f0fb15SPaul Saab if (get_ifile(good_filename, curr_ifile) == curr_ifile)
727a5f0fb15SPaul Saab {
728a5f0fb15SPaul Saab /*
729a5f0fb15SPaul Saab * Trying to edit the current file; don't reopen it.
730a5f0fb15SPaul Saab */
731a5f0fb15SPaul Saab unsave_ifile(save_ifile);
732a5f0fb15SPaul Saab return (0);
733a5f0fb15SPaul Saab }
734a5f0fb15SPaul Saab reedit_ifile(save_ifile);
735a5f0fb15SPaul Saab return (edit(good_filename));
736a5f0fb15SPaul Saab }
737a5f0fb15SPaul Saab
738a5f0fb15SPaul Saab /*
739a5f0fb15SPaul Saab * Edit the first file in the command line (ifile) list.
740a5f0fb15SPaul Saab */
edit_first(void)741d713e089SXin LI public int edit_first(void)
742a5f0fb15SPaul Saab {
743b7780dbeSXin LI if (nifile() == 0)
744b7780dbeSXin LI return (edit_stdin());
745a5f0fb15SPaul Saab curr_ifile = NULL_IFILE;
746a5f0fb15SPaul Saab return (edit_next(1));
747a5f0fb15SPaul Saab }
748a5f0fb15SPaul Saab
749a5f0fb15SPaul Saab /*
750a5f0fb15SPaul Saab * Edit the last file in the command line (ifile) list.
751a5f0fb15SPaul Saab */
edit_last(void)752d713e089SXin LI public int edit_last(void)
753a5f0fb15SPaul Saab {
754a5f0fb15SPaul Saab curr_ifile = NULL_IFILE;
755a5f0fb15SPaul Saab return (edit_prev(1));
756a5f0fb15SPaul Saab }
757a5f0fb15SPaul Saab
758a5f0fb15SPaul Saab
759a5f0fb15SPaul Saab /*
7606dcb072bSXin LI * Edit the n-th next or previous file in the command line (ifile) list.
761a5f0fb15SPaul Saab */
edit_istep(IFILE h,int n,int dir)762d713e089SXin LI static int edit_istep(IFILE h, int n, int dir)
763a5f0fb15SPaul Saab {
764a5f0fb15SPaul Saab IFILE next;
765a5f0fb15SPaul Saab
766a5f0fb15SPaul Saab /*
767a5f0fb15SPaul Saab * Skip n filenames, then try to edit each filename.
768a5f0fb15SPaul Saab */
769a5f0fb15SPaul Saab for (;;)
770a5f0fb15SPaul Saab {
771a5f0fb15SPaul Saab next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
772a5f0fb15SPaul Saab if (--n < 0)
773a5f0fb15SPaul Saab {
774a5f0fb15SPaul Saab if (edit_ifile(h) == 0)
775a5f0fb15SPaul Saab break;
776a5f0fb15SPaul Saab }
777a5f0fb15SPaul Saab if (next == NULL_IFILE)
778a5f0fb15SPaul Saab {
779a5f0fb15SPaul Saab /*
780a5f0fb15SPaul Saab * Reached end of the ifile list.
781a5f0fb15SPaul Saab */
782a5f0fb15SPaul Saab return (1);
783a5f0fb15SPaul Saab }
784a5f0fb15SPaul Saab if (ABORT_SIGS())
785a5f0fb15SPaul Saab {
786a5f0fb15SPaul Saab /*
787a5f0fb15SPaul Saab * Interrupt breaks out, if we're in a long
788a5f0fb15SPaul Saab * list of files that can't be opened.
789a5f0fb15SPaul Saab */
790a5f0fb15SPaul Saab return (1);
791a5f0fb15SPaul Saab }
792a5f0fb15SPaul Saab h = next;
793a5f0fb15SPaul Saab }
794a5f0fb15SPaul Saab /*
795a5f0fb15SPaul Saab * Found a file that we can edit.
796a5f0fb15SPaul Saab */
797a5f0fb15SPaul Saab return (0);
798a5f0fb15SPaul Saab }
799a5f0fb15SPaul Saab
edit_inext(IFILE h,int n)800d713e089SXin LI static int edit_inext(IFILE h, int n)
801a5f0fb15SPaul Saab {
8026dcb072bSXin LI return (edit_istep(h, n, +1));
803a5f0fb15SPaul Saab }
804a5f0fb15SPaul Saab
edit_next(int n)805d713e089SXin LI public int edit_next(int n)
806a5f0fb15SPaul Saab {
8076dcb072bSXin LI return edit_istep(curr_ifile, n, +1);
808a5f0fb15SPaul Saab }
809a5f0fb15SPaul Saab
edit_iprev(IFILE h,int n)810d713e089SXin LI static int edit_iprev(IFILE h, int n)
811a5f0fb15SPaul Saab {
812a5f0fb15SPaul Saab return (edit_istep(h, n, -1));
813a5f0fb15SPaul Saab }
814a5f0fb15SPaul Saab
edit_prev(int n)815d713e089SXin LI public int edit_prev(int n)
816a5f0fb15SPaul Saab {
817a5f0fb15SPaul Saab return edit_istep(curr_ifile, n, -1);
818a5f0fb15SPaul Saab }
819a5f0fb15SPaul Saab
820a5f0fb15SPaul Saab /*
821a5f0fb15SPaul Saab * Edit a specific file in the command line (ifile) list.
822a5f0fb15SPaul Saab */
edit_index(int n)823d713e089SXin LI public int edit_index(int n)
824a5f0fb15SPaul Saab {
825a5f0fb15SPaul Saab IFILE h;
826a5f0fb15SPaul Saab
827a5f0fb15SPaul Saab h = NULL_IFILE;
828a5f0fb15SPaul Saab do
829a5f0fb15SPaul Saab {
830a5f0fb15SPaul Saab if ((h = next_ifile(h)) == NULL_IFILE)
831a5f0fb15SPaul Saab {
832a5f0fb15SPaul Saab /*
833a5f0fb15SPaul Saab * Reached end of the list without finding it.
834a5f0fb15SPaul Saab */
835a5f0fb15SPaul Saab return (1);
836a5f0fb15SPaul Saab }
837a5f0fb15SPaul Saab } while (get_index(h) != n);
838a5f0fb15SPaul Saab
839a5f0fb15SPaul Saab return (edit_ifile(h));
840a5f0fb15SPaul Saab }
841a5f0fb15SPaul Saab
save_curr_ifile(void)842d713e089SXin LI public IFILE save_curr_ifile(void)
843a5f0fb15SPaul Saab {
844a5f0fb15SPaul Saab if (curr_ifile != NULL_IFILE)
845a5f0fb15SPaul Saab hold_ifile(curr_ifile, 1);
846a5f0fb15SPaul Saab return (curr_ifile);
847a5f0fb15SPaul Saab }
848a5f0fb15SPaul Saab
unsave_ifile(IFILE save_ifile)849d713e089SXin LI public void unsave_ifile(IFILE save_ifile)
850a5f0fb15SPaul Saab {
851a5f0fb15SPaul Saab if (save_ifile != NULL_IFILE)
852a5f0fb15SPaul Saab hold_ifile(save_ifile, -1);
853a5f0fb15SPaul Saab }
854a5f0fb15SPaul Saab
855a5f0fb15SPaul Saab /*
856a5f0fb15SPaul Saab * Reedit the ifile which was previously open.
857a5f0fb15SPaul Saab */
reedit_ifile(IFILE save_ifile)858d713e089SXin LI public void reedit_ifile(IFILE save_ifile)
859a5f0fb15SPaul Saab {
860a5f0fb15SPaul Saab IFILE next;
861a5f0fb15SPaul Saab IFILE prev;
862a5f0fb15SPaul Saab
863a5f0fb15SPaul Saab /*
864a5f0fb15SPaul Saab * Try to reopen the ifile.
865a5f0fb15SPaul Saab * Note that opening it may fail (maybe the file was removed),
866a5f0fb15SPaul Saab * in which case the ifile will be deleted from the list.
867a5f0fb15SPaul Saab * So save the next and prev ifiles first.
868a5f0fb15SPaul Saab */
869a5f0fb15SPaul Saab unsave_ifile(save_ifile);
870a5f0fb15SPaul Saab next = next_ifile(save_ifile);
871a5f0fb15SPaul Saab prev = prev_ifile(save_ifile);
872a5f0fb15SPaul Saab if (edit_ifile(save_ifile) == 0)
873a5f0fb15SPaul Saab return;
874a5f0fb15SPaul Saab /*
875a5f0fb15SPaul Saab * If can't reopen it, open the next input file in the list.
876a5f0fb15SPaul Saab */
877a5f0fb15SPaul Saab if (next != NULL_IFILE && edit_inext(next, 0) == 0)
878a5f0fb15SPaul Saab return;
879a5f0fb15SPaul Saab /*
880a5f0fb15SPaul Saab * If can't open THAT one, open the previous input file in the list.
881a5f0fb15SPaul Saab */
882a5f0fb15SPaul Saab if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
883a5f0fb15SPaul Saab return;
884a5f0fb15SPaul Saab /*
885a5f0fb15SPaul Saab * If can't even open that, we're stuck. Just quit.
886a5f0fb15SPaul Saab */
887a5f0fb15SPaul Saab quit(QUIT_ERROR);
888a5f0fb15SPaul Saab }
889a5f0fb15SPaul Saab
reopen_curr_ifile(void)890d713e089SXin LI public void reopen_curr_ifile(void)
891464501a8SXin LI {
892464501a8SXin LI IFILE save_ifile = save_curr_ifile();
893464501a8SXin LI close_file();
894464501a8SXin LI reedit_ifile(save_ifile);
895464501a8SXin LI }
896464501a8SXin LI
897a5f0fb15SPaul Saab /*
898a5f0fb15SPaul Saab * Edit standard input.
899a5f0fb15SPaul Saab */
edit_stdin(void)900d713e089SXin LI public int edit_stdin(void)
901a5f0fb15SPaul Saab {
902a5f0fb15SPaul Saab if (isatty(fd0))
903a5f0fb15SPaul Saab {
904a5f0fb15SPaul Saab error("Missing filename (\"less --help\" for help)", NULL_PARG);
905a5f0fb15SPaul Saab quit(QUIT_OK);
906a5f0fb15SPaul Saab }
907a5f0fb15SPaul Saab return (edit("-"));
908a5f0fb15SPaul Saab }
909a5f0fb15SPaul Saab
910a5f0fb15SPaul Saab /*
911a5f0fb15SPaul Saab * Copy a file directly to standard output.
912a5f0fb15SPaul Saab * Used if standard output is not a tty.
913a5f0fb15SPaul Saab */
cat_file(void)914d713e089SXin LI public void cat_file(void)
915a5f0fb15SPaul Saab {
9161ea31627SRobert Watson int c;
917a5f0fb15SPaul Saab
918a5f0fb15SPaul Saab while ((c = ch_forw_get()) != EOI)
919a5f0fb15SPaul Saab putchr(c);
920a5f0fb15SPaul Saab flush();
921a5f0fb15SPaul Saab }
922a5f0fb15SPaul Saab
923a5f0fb15SPaul Saab #if LOGFILE
924a5f0fb15SPaul Saab
9252235c7feSXin LI #define OVERWRITE_OPTIONS "Overwrite, Append, Don't log, or Quit?"
9262235c7feSXin LI
927a5f0fb15SPaul Saab /*
928a5f0fb15SPaul Saab * If the user asked for a log file and our input file
929a5f0fb15SPaul Saab * is standard input, create the log file.
930a5f0fb15SPaul Saab * We take care not to blindly overwrite an existing file.
931a5f0fb15SPaul Saab */
use_logfile(char * filename)932d713e089SXin LI public void use_logfile(char *filename)
933a5f0fb15SPaul Saab {
9341ea31627SRobert Watson int exists;
9351ea31627SRobert Watson int answer;
936a5f0fb15SPaul Saab PARG parg;
937a5f0fb15SPaul Saab
938a5f0fb15SPaul Saab if (ch_getflags() & CH_CANSEEK)
939a5f0fb15SPaul Saab /*
940a5f0fb15SPaul Saab * Can't currently use a log file on a file that can seek.
941a5f0fb15SPaul Saab */
942a5f0fb15SPaul Saab return;
943a5f0fb15SPaul Saab
944a5f0fb15SPaul Saab /*
945a5f0fb15SPaul Saab * {{ We could use access() here. }}
946a5f0fb15SPaul Saab */
947a5f0fb15SPaul Saab exists = open(filename, OPEN_READ);
948a15691bfSXin LI if (exists >= 0)
949a5f0fb15SPaul Saab close(exists);
950a5f0fb15SPaul Saab exists = (exists >= 0);
951a5f0fb15SPaul Saab
952a5f0fb15SPaul Saab /*
953a5f0fb15SPaul Saab * Decide whether to overwrite the log file or append to it.
954a5f0fb15SPaul Saab * If it doesn't exist we "overwrite" it.
955a5f0fb15SPaul Saab */
956a5f0fb15SPaul Saab if (!exists || force_logfile)
957a5f0fb15SPaul Saab {
958a5f0fb15SPaul Saab /*
959a5f0fb15SPaul Saab * Overwrite (or create) the log file.
960a5f0fb15SPaul Saab */
961a5f0fb15SPaul Saab answer = 'O';
962a5f0fb15SPaul Saab } else
963a5f0fb15SPaul Saab {
964a5f0fb15SPaul Saab /*
965a5f0fb15SPaul Saab * Ask user what to do.
966a5f0fb15SPaul Saab */
967a5f0fb15SPaul Saab parg.p_string = filename;
9682235c7feSXin LI answer = query("Warning: \"%s\" exists; "OVERWRITE_OPTIONS" ", &parg);
969a5f0fb15SPaul Saab }
970a5f0fb15SPaul Saab
971a5f0fb15SPaul Saab loop:
972a5f0fb15SPaul Saab switch (answer)
973a5f0fb15SPaul Saab {
974a5f0fb15SPaul Saab case 'O': case 'o':
975a5f0fb15SPaul Saab /*
976a5f0fb15SPaul Saab * Overwrite: create the file.
977a5f0fb15SPaul Saab */
978f80a33eaSXin LI logfile = creat(filename, CREAT_RW);
979a5f0fb15SPaul Saab break;
980a5f0fb15SPaul Saab case 'A': case 'a':
981a5f0fb15SPaul Saab /*
982a5f0fb15SPaul Saab * Append: open the file and seek to the end.
983a5f0fb15SPaul Saab */
984a5f0fb15SPaul Saab logfile = open(filename, OPEN_APPEND);
985464501a8SXin LI if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK)
986a5f0fb15SPaul Saab {
987a5f0fb15SPaul Saab close(logfile);
988a5f0fb15SPaul Saab logfile = -1;
989a5f0fb15SPaul Saab }
990a5f0fb15SPaul Saab break;
991a5f0fb15SPaul Saab case 'D': case 'd':
992a5f0fb15SPaul Saab /*
993a5f0fb15SPaul Saab * Don't do anything.
994a5f0fb15SPaul Saab */
995a5f0fb15SPaul Saab return;
996a5f0fb15SPaul Saab default:
997a5f0fb15SPaul Saab /*
998a5f0fb15SPaul Saab * Eh?
999a5f0fb15SPaul Saab */
10002235c7feSXin LI
10012235c7feSXin LI answer = query(OVERWRITE_OPTIONS" (Type \"O\", \"A\", \"D\" or \"Q\") ", NULL_PARG);
1002a5f0fb15SPaul Saab goto loop;
1003a5f0fb15SPaul Saab }
1004a5f0fb15SPaul Saab
1005a5f0fb15SPaul Saab if (logfile < 0)
1006a5f0fb15SPaul Saab {
1007a5f0fb15SPaul Saab /*
1008a5f0fb15SPaul Saab * Error in opening logfile.
1009a5f0fb15SPaul Saab */
1010a5f0fb15SPaul Saab parg.p_string = filename;
1011a5f0fb15SPaul Saab error("Cannot write to \"%s\"", &parg);
1012a5f0fb15SPaul Saab return;
1013a5f0fb15SPaul Saab }
1014a5f0fb15SPaul Saab SET_BINARY(logfile);
1015a5f0fb15SPaul Saab }
1016a5f0fb15SPaul Saab
1017a5f0fb15SPaul Saab #endif
1018