Mercurial > hg > Applications > mh
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 |