comparison miscellany/less-177/edit.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:bce86c4163a3
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