Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / edit.c
1 #include "less.h"
2
3 #if __MSDOS__
4 #include <fcntl.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <io.h>
8 #endif
9
10 #define ISPIPE(fd)      ((fd)==0)
11 extern int ispipe;
12 extern int new_file;
13 extern int errmsgs;
14 extern int quit_at_eof;
15 extern int file;
16 extern int cbufs;
17 extern char *every_first_cmd;
18 extern int any_display;
19 extern int force_open;
20 extern int is_tty;
21 extern IFILE curr_ifile;
22 extern IFILE old_ifile;
23 extern struct scrpos initial_scrpos;
24
25 #if LOGFILE
26 extern int logfile;
27 extern int force_logfile;
28 extern char *namelogfile;
29 #endif
30
31
32 /*
33  * Edit a new file.
34  * Filename == "-" means standard input.
35  * Filename == NULL means just close the current file.
36  */
37         public int
38 edit(filename, just_looking)
39         register char *filename;
40         int just_looking;
41 {
42         register int f;
43         char *s;
44         int answer;
45         int no_display;
46         struct scrpos scrpos;
47         PARG parg;
48
49         if (filename == NULL)
50         {
51                 /*
52                  * Close the current file, but don't open a new one.
53                  */
54                 f = -1;
55         } else if (strcmp(filename, "-") == 0)
56         {
57                 /* 
58                  * Use standard input.
59                  */
60                 f = 0;
61         } else if ((parg.p_string = bad_file(filename)) != NULL)
62         {
63                 error("%s", &parg);
64                 free(parg.p_string);
65                 return (1);
66 #if __MSDOS__
67         } else if ((f = open(filename, O_RDONLY|O_BINARY)) < 0)
68 #else
69         } else if ((f = open(filename, 0)) < 0)
70 #endif
71         {
72                 parg.p_string = errno_message(filename);
73                 error("%s", &parg);
74                 free(parg.p_string);
75                 return (1);
76         } else if (!force_open && !just_looking && bin_file(f))
77         {
78                 parg.p_string = filename;
79                 answer = query("\"%s\" may be a binary file.  Continue? ",
80                         &parg);
81                 if (answer != 'y' && answer != 'Y')
82                 {
83                         close(f);
84                         return (1);
85                 }
86         }
87
88         if (f >= 0 && isatty(f))
89         {
90                 /*
91                  * Not really necessary to call this an error,
92                  * but if the control terminal (for commands)
93                  * and the input file (for data) are the same,
94                  * we get weird results at best.
95                  */
96 #if __MSDOS__
97                 parg.p_string = "less -?";
98 #else
99                 parg.p_string = "less -\\?";
100 #endif
101                 error("Cannot take input from a terminal (\"%s\" for help)", 
102                         &parg);
103                 if (!ISPIPE(f))
104                         close(f);
105                 return (1);
106         }
107
108 #if LOGFILE
109         s = namelogfile;
110         end_logfile();
111         if (f >= 0 && ISPIPE(f) && s != NULL && is_tty)
112                 use_logfile(s);
113 #endif
114
115         /*
116          * We are now committed to using the new file.
117          * Close the current input file and set up to use the new one.
118          */
119         if (curr_ifile != NULL_IFILE)
120         {
121                 /*
122                  * Save the current position so that we can return to
123                  * the same position if we edit this file again.
124                  */
125                 get_scrpos(&scrpos);
126                 if (scrpos.pos != NULL_POSITION)
127                 {
128                         store_pos(curr_ifile, &scrpos);
129                         lastmark();
130                 }
131         }
132
133         /*
134          * Close the current file, unless it is a pipe.
135          */
136         if (!ISPIPE(file))
137                 close(file);
138         file = f;
139
140         if (f < 0)
141                 return (1);
142
143         /*
144          * Get the new ifile.
145          * Get the saved position for that file.
146          */
147         old_ifile = curr_ifile;
148         curr_ifile = get_ifile(filename, curr_ifile);
149         get_pos(curr_ifile, &initial_scrpos);
150
151         ispipe = ISPIPE(f);
152         if (ispipe)
153                 ch_pipe();
154         else
155                 ch_nonpipe();
156         (void) ch_nbuf(cbufs);
157         ch_flush();
158
159         new_file = 1;
160
161 #if  __MSDOS__
162         top_filename();
163 #endif
164
165         if (every_first_cmd != NULL)
166                 ungetsc(every_first_cmd);
167
168         no_display = !any_display;
169         flush();
170         any_display = 1;
171
172         if (is_tty)
173         {
174                 /*
175                  * Output is to a real tty.
176                  */
177
178                 /*
179                  * Indicate there is nothing displayed yet.
180                  */
181                 pos_clear();
182                 clr_linenum();
183                 if (no_display && errmsgs > 0)
184                 {
185                         /*
186                          * We displayed some messages on error output
187                          * (file descriptor 2; see error() function).
188                          * Before erasing the screen contents,
189                          * display the file name and wait for a keystroke.
190                          */
191                         parg.p_string = filename;
192                         error("%s", &parg);
193                 }
194         }
195         return (0);
196 }
197
198 /*
199  * Edit a space-separated list of files.
200  * For each filename in the list, enter it into the ifile list.
201  * Then edit the first one.
202  */
203         public void
204 edit_list(list)
205         char *list;
206 {
207         register char *s;
208         register char *es;
209         register char *filename;
210         char *good_filename;
211         IFILE save_curr_ifile;
212
213         /*
214          * good_filename keeps track of the first valid filename.
215          */
216         good_filename = NULL;
217         s = list;
218         es = s + strlen(s);
219         save_curr_ifile = curr_ifile;
220         while ((s = skipsp(s)) < es)
221         {
222                 /*
223                  * Get the next filename and null terminate it.
224                  */
225                 filename = s;
226                 while (*s != ' ' && *s != '\0')
227                         s++;
228                 if (*s != '\0')
229                         *s++ = '\0';
230                 /*
231                  * Try to edit the file.
232                  * This enters it into the command line list (if it is good).
233                  * If it is the first good file we've seen, remember it.
234                  * {{ A little weirdness here: if any of the filenames
235                  *    are already in the list, subsequent ones get
236                  *    entered after the position where that one already
237                  *    was, instead of at the end. }}
238                  */
239                 if (edit(filename, 1) == 0 && good_filename == NULL)
240                         good_filename = filename;
241         }
242
243         /*
244          * Edit the first valid filename in the list.
245          */
246         if (good_filename != NULL)
247         {
248                 curr_ifile = save_curr_ifile;
249                 (void) edit(good_filename, 0);
250         }
251 }
252
253 /*
254  * Edit the first file in the command line (ifile) list.
255  */
256         public int
257 edit_first()
258 {
259         curr_ifile = NULL_IFILE;
260         return (edit_next(1));
261 }
262
263 /*
264  * Edit the last file in the command line (ifile) list.
265  */
266         public int
267 edit_last()
268 {
269         curr_ifile = NULL_IFILE;
270         return (edit_prev(1));
271 }
272
273
274 /*
275  * Edit the next file in the command line (ifile) list.
276  */
277         public int
278 edit_next(n)
279         int n;
280 {
281         IFILE h;
282
283         h = curr_ifile;
284         while (--n >= 0 || edit(get_filename(h), 0))
285         {
286                 if ((h = next_ifile(h)) == NULL_IFILE)
287                         /*
288                          * Reached end of the ifile list.
289                          */
290                         return (1);
291         } 
292         /*
293          * Found a file that we can edit.
294          */
295         return (0);
296 }
297
298 /*
299  * Edit the previous file in the command line list.
300  */
301         public int
302 edit_prev(n)
303         int n;
304 {
305         IFILE h;
306
307         h = curr_ifile;
308         while (--n >= 0 || edit(get_filename(h), 0))
309         {
310                 if ((h = prev_ifile(h)) == NULL_IFILE)
311                         /*
312                          * Reached beginning of the ifile list.
313                          */
314                         return (1);
315         } 
316         /*
317          * Found a file that we can edit.
318          */
319         return (0);
320 }
321
322 /*
323  * Edit a specific file in the command line (ifile) list.
324  */
325         public int
326 edit_index(n)
327         int n;
328 {
329         IFILE h;
330
331         h = NULL_IFILE;
332         do
333         {
334                 if ((h = next_ifile(h)) == NULL_IFILE)
335                 {
336                         /*
337                          * Reached end of the list without finding it.
338                          */
339                         return (1);
340                 }
341         } while (get_index(h) != n);
342
343         return (edit(get_filename(h), 0));
344 }
345
346 /*
347  * Copy a file directly to standard output.
348  * Used if standard output is not a tty.
349  */
350         public void
351 cat_file()
352 {
353         register int c;
354
355         while ((c = ch_forw_get()) != EOI)
356                 putchr(c);
357         flush();
358 }
359
360 #if LOGFILE
361
362 /*
363  * If the user asked for a log file and our input file
364  * is standard input, create the log file.  
365  * We take care not to blindly overwrite an existing file.
366  */
367         public void
368 use_logfile(filename)
369         char *filename;
370 {
371         register int exists;
372         register int answer;
373         PARG parg;
374
375         /*
376          * {{ We could use access() here. }}
377          */
378         exists = open(filename, 0);
379         close(exists);
380         exists = (exists >= 0);
381
382         /*
383          * Decide whether to overwrite the log file or append to it.
384          * (If it doesn't exist we "overwrite" it.
385          */
386         if (!exists || force_logfile)
387         {
388                 /*
389                  * Overwrite (or create) the log file.
390                  */
391                 answer = 'O';
392         } else
393         {
394                 /*
395                  * Ask user what to do.
396                  */
397                 parg.p_string = filename;
398                 answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg);
399         }
400
401 loop:
402         switch (answer)
403         {
404         case 'O': case 'o':
405                 /*
406                  * Overwrite: create the file.
407                  */
408                 logfile = creat(filename, 0644);
409                 break;
410         case 'A': case 'a':
411                 /*
412                  * Append: open the file and seek to the end.
413                  */
414 #if __MSDOS__
415                 logfile = open(filename, O_APPEND|O_WRONLY);
416 #else
417                 logfile = open(filename, 1);
418 #endif
419                 if (lseek(logfile, (offset_t)0, 2) == BAD_LSEEK)
420                 {
421                         close(logfile);
422                         logfile = -1;
423                 }
424                 break;
425         case 'D': case 'd':
426                 /*
427                  * Don't do anything.
428                  */
429                 return;
430         case 'q':
431                 quit(0);
432                 /*NOTREACHED*/
433         default:
434                 /*
435                  * Eh?
436                  */
437                 answer = query("Overwrite, Append, or Don't log? ", NULL_PARG);
438                 goto loop;
439         }
440
441         if (logfile < 0)
442         {
443                 /*
444                  * Error in opening logfile.
445                  */
446                 parg.p_string = filename;
447                 error("Cannot write to \"%s\"", &parg);
448         }
449 }
450
451 #endif