edit.c (7e1b7636c894be9d1130c284089ce1ea0786ecec) edit.c (b2ea244070ff84eab79e04befb7aa30c982fc84d)
1/*
2 * Copyright (C) 1984-2017 Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information, see the README file.
8 */
9
10
11#include "less.h"
1/*
2 * Copyright (C) 1984-2017 Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information, see the README file.
8 */
9
10
11#include "less.h"
12#include "position.h"
12#if HAVE_STAT
13#include <sys/stat.h>
14#endif
13#if HAVE_STAT
14#include <sys/stat.h>
15#endif
16#if OS2
17#include <signal.h>
18#endif
15
16public int fd0 = 0;
17
18extern int new_file;
19extern int errmsgs;
20extern int cbufs;
21extern char *every_first_cmd;
22extern int any_display;

--- 15 unchanged lines hidden (view full) ---

38extern char *namelogfile;
39#endif
40
41#if HAVE_STAT_INO
42public dev_t curr_dev;
43public ino_t curr_ino;
44#endif
45
19
20public int fd0 = 0;
21
22extern int new_file;
23extern int errmsgs;
24extern int cbufs;
25extern char *every_first_cmd;
26extern int any_display;

--- 15 unchanged lines hidden (view full) ---

42extern char *namelogfile;
43#endif
44
45#if HAVE_STAT_INO
46public dev_t curr_dev;
47public ino_t curr_ino;
48#endif
49
46char *curr_altfilename = NULL;
47static void *curr_altpipe;
48
50
49
50/*
51 * Textlist functions deal with a list of words separated by spaces.
52 * init_textlist sets up a textlist structure.
53 * forw_textlist uses that structure to iterate thru the list of
54 * words, returning each one as a standard null-terminated string.
55 * back_textlist does the same, but runs thru the list backwards.
56 */
57 public void

--- 86 unchanged lines hidden (view full) ---

144 if (s <= tlist->string)
145 return (NULL);
146 while (s[-1] != '\0' && s > tlist->string)
147 s--;
148 return (s);
149}
150
151/*
51/*
52 * Textlist functions deal with a list of words separated by spaces.
53 * init_textlist sets up a textlist structure.
54 * forw_textlist uses that structure to iterate thru the list of
55 * words, returning each one as a standard null-terminated string.
56 * back_textlist does the same, but runs thru the list backwards.
57 */
58 public void

--- 86 unchanged lines hidden (view full) ---

145 if (s <= tlist->string)
146 return (NULL);
147 while (s[-1] != '\0' && s > tlist->string)
148 s--;
149 return (s);
150}
151
152/*
153 * Close a pipe opened via popen.
154 */
155 static void
156close_pipe(FILE *pipefd)
157{
158 if (pipefd == NULL)
159 return;
160#if OS2
161 /*
162 * The pclose function of OS/2 emx sometimes fails.
163 * Send SIGINT to the piped process before closing it.
164 */
165 kill(pipefd->_pid, SIGINT);
166#endif
167 pclose(pipefd);
168}
169
170/*
152 * Close the current input file.
153 */
154 static void
155close_file()
156{
157 struct scrpos scrpos;
171 * Close the current input file.
172 */
173 static void
174close_file()
175{
176 struct scrpos scrpos;
177 int chflags;
178 FILE *altpipe;
179 char *altfilename;
158
159 if (curr_ifile == NULL_IFILE)
160 return;
161
162 /*
163 * Save the current position so that we can return to
164 * the same position if we edit this file again.
165 */
180
181 if (curr_ifile == NULL_IFILE)
182 return;
183
184 /*
185 * Save the current position so that we can return to
186 * the same position if we edit this file again.
187 */
166 get_scrpos(&scrpos);
188 get_scrpos(&scrpos, TOP);
167 if (scrpos.pos != NULL_POSITION)
168 {
169 store_pos(curr_ifile, &scrpos);
170 lastmark();
171 }
172 /*
173 * Close the file descriptor, unless it is a pipe.
174 */
189 if (scrpos.pos != NULL_POSITION)
190 {
191 store_pos(curr_ifile, &scrpos);
192 lastmark();
193 }
194 /*
195 * Close the file descriptor, unless it is a pipe.
196 */
197 chflags = ch_getflags();
175 ch_close();
176 /*
177 * If we opened a file using an alternate name,
178 * do special stuff to close it.
179 */
198 ch_close();
199 /*
200 * If we opened a file using an alternate name,
201 * do special stuff to close it.
202 */
180 if (curr_altfilename != NULL)
203 altfilename = get_altfilename(curr_ifile);
204 if (altfilename != NULL)
181 {
205 {
182 close_altfile(curr_altfilename, get_filename(curr_ifile),
183 curr_altpipe);
184 free(curr_altfilename);
185 curr_altfilename = NULL;
206 altpipe = get_altpipe(curr_ifile);
207 if (altpipe != NULL && !(chflags & CH_KEEPOPEN))
208 {
209 close_pipe(altpipe);
210 set_altpipe(curr_ifile, NULL);
211 }
212 close_altfile(altfilename, get_filename(curr_ifile));
213 set_altfilename(curr_ifile, NULL);
186 }
187 curr_ifile = NULL_IFILE;
188#if HAVE_STAT_INO
189 curr_ino = curr_dev = 0;
190#endif
191}
192
193/*

--- 19 unchanged lines hidden (view full) ---

213 IFILE ifile;
214{
215 int f;
216 int answer;
217 int no_display;
218 int chflags;
219 char *filename;
220 char *open_filename;
214 }
215 curr_ifile = NULL_IFILE;
216#if HAVE_STAT_INO
217 curr_ino = curr_dev = 0;
218#endif
219}
220
221/*

--- 19 unchanged lines hidden (view full) ---

241 IFILE ifile;
242{
243 int f;
244 int answer;
245 int no_display;
246 int chflags;
247 char *filename;
248 char *open_filename;
221 char *qopen_filename;
222 char *alt_filename;
249 char *alt_filename;
223 void *alt_pipe;
250 void *altpipe;
224 IFILE was_curr_ifile;
225 PARG parg;
226
227 if (ifile == curr_ifile)
228 {
229 /*
230 * Already have the correct file open.
231 */

--- 33 unchanged lines hidden (view full) ---

265 * you're supposed to have saved curr_ifile yourself,
266 * and you'll restore it if necessary.)
267 */
268 unsave_ifile(was_curr_ifile);
269 return (0);
270 }
271
272 filename = save(get_filename(ifile));
251 IFILE was_curr_ifile;
252 PARG parg;
253
254 if (ifile == curr_ifile)
255 {
256 /*
257 * Already have the correct file open.
258 */

--- 33 unchanged lines hidden (view full) ---

292 * you're supposed to have saved curr_ifile yourself,
293 * and you'll restore it if necessary.)
294 */
295 unsave_ifile(was_curr_ifile);
296 return (0);
297 }
298
299 filename = save(get_filename(ifile));
300
273 /*
274 * See if LESSOPEN specifies an "alternate" file to open.
275 */
301 /*
302 * See if LESSOPEN specifies an "alternate" file to open.
303 */
276 alt_pipe = NULL;
277 alt_filename = open_altfile(filename, &f, &alt_pipe);
278 open_filename = (alt_filename != NULL) ? alt_filename : filename;
279 qopen_filename = shell_unquote(open_filename);
280
281 chflags = 0;
282 if (alt_pipe != NULL)
304 altpipe = get_altpipe(ifile);
305 if (altpipe != NULL)
283 {
284 /*
306 {
307 /*
285 * The alternate "file" is actually a pipe.
286 * f has already been set to the file descriptor of the pipe
287 * in the call to open_altfile above.
288 * Keep the file descriptor open because it was opened
289 * via popen(), and pclose() wants to close it.
308 * File is already open.
309 * chflags and f are not used by ch_init if ifile has
310 * filestate which should be the case if we're here.
311 * Set them here to avoid uninitialized variable warnings.
290 */
312 */
291 chflags |= CH_POPENED;
292 } else if (strcmp(open_filename, "-") == 0)
293 {
294 /*
295 * Use standard input.
296 * Keep the file descriptor open because we can't reopen it.
297 */
298 f = fd0;
299 chflags |= CH_KEEPOPEN;
300 /*
301 * Must switch stdin to BINARY mode.
302 */
303 SET_BINARY(f);
304#if MSDOS_COMPILER==DJGPPC
305 /*
306 * Setting stdin to binary by default causes
307 * Ctrl-C to not raise SIGINT. We must undo
308 * that side-effect.
309 */
310 __djgpp_set_ctrl_c(1);
311#endif
312 } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
313 {
313 chflags = 0;
314 f = -1;
314 f = -1;
315 chflags |= CH_NODATA;
316 } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
315 alt_filename = get_altfilename(ifile);
316 open_filename = (alt_filename != NULL) ? alt_filename : filename;
317 } else
317 {
318 {
318 f = -1;
319 chflags |= CH_HELPFILE;
320 } else if ((parg.p_string = bad_file(open_filename)) != NULL)
321 {
322 /*
323 * It looks like a bad file. Don't try to open it.
324 */
325 error("%s", &parg);
326 free(parg.p_string);
327 err1:
328 if (alt_filename != NULL)
319 if (strcmp(filename, FAKE_HELPFILE) == 0 ||
320 strcmp(filename, FAKE_EMPTYFILE) == 0)
321 alt_filename = NULL;
322 else
323 alt_filename = open_altfile(filename, &f, &altpipe);
324
325 open_filename = (alt_filename != NULL) ? alt_filename : filename;
326
327 chflags = 0;
328 if (altpipe != NULL)
329 {
329 {
330 close_altfile(alt_filename, filename, alt_pipe);
331 free(alt_filename);
332 }
333 del_ifile(ifile);
334 free(qopen_filename);
335 free(filename);
336 /*
337 * Re-open the current file.
338 */
339 if (was_curr_ifile == ifile)
330 /*
331 * The alternate "file" is actually a pipe.
332 * f has already been set to the file descriptor of the pipe
333 * in the call to open_altfile above.
334 * Keep the file descriptor open because it was opened
335 * via popen(), and pclose() wants to close it.
336 */
337 chflags |= CH_POPENED;
338 if (strcmp(filename, "-") == 0)
339 chflags |= CH_KEEPOPEN;
340 } else if (strcmp(filename, "-") == 0)
340 {
341 {
342 /*
343 * Use standard input.
344 * Keep the file descriptor open because we can't reopen it.
345 */
346 f = fd0;
347 chflags |= CH_KEEPOPEN;
341 /*
348 /*
342 * Whoops. The "current" ifile is the one we just deleted.
343 * Just give up.
349 * Must switch stdin to BINARY mode.
344 */
350 */
345 quit(QUIT_ERROR);
346 }
347 reedit_ifile(was_curr_ifile);
348 return (1);
349 } else if ((f = open(qopen_filename, OPEN_READ)) < 0)
350 {
351 /*
352 * Got an error trying to open it.
353 */
354 parg.p_string = errno_message(filename);
355 error("%s", &parg);
356 free(parg.p_string);
357 goto err1;
358 } else
359 {
360 chflags |= CH_CANSEEK;
361 if (!force_open && !opened(ifile) && bin_file(f))
351 SET_BINARY(f);
352#if MSDOS_COMPILER==DJGPPC
353 /*
354 * Setting stdin to binary by default causes
355 * Ctrl-C to not raise SIGINT. We must undo
356 * that side-effect.
357 */
358 __djgpp_set_ctrl_c(1);
359#endif
360 } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
362 {
361 {
362 f = -1;
363 chflags |= CH_NODATA;
364 } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
365 {
366 f = -1;
367 chflags |= CH_HELPFILE;
368 } else if ((parg.p_string = bad_file(open_filename)) != NULL)
369 {
363 /*
370 /*
364 * Looks like a binary file.
365 * Ask user if we should proceed.
371 * It looks like a bad file. Don't try to open it.
366 */
372 */
367 parg.p_string = filename;
368 answer = query("\"%s\" may be a binary file. See it anyway? ",
369 &parg);
370 if (answer != 'y' && answer != 'Y')
373 error("%s", &parg);
374 free(parg.p_string);
375 err1:
376 if (alt_filename != NULL)
371 {
377 {
372 close(f);
378 close_pipe(altpipe);
379 close_altfile(alt_filename, filename);
380 free(alt_filename);
381 }
382 del_ifile(ifile);
383 free(filename);
384 /*
385 * Re-open the current file.
386 */
387 if (was_curr_ifile == ifile)
388 {
389 /*
390 * Whoops. The "current" ifile is the one we just deleted.
391 * Just give up.
392 */
393 quit(QUIT_ERROR);
394 }
395 reedit_ifile(was_curr_ifile);
396 return (1);
397 } else if ((f = open(open_filename, OPEN_READ)) < 0)
398 {
399 /*
400 * Got an error trying to open it.
401 */
402 parg.p_string = errno_message(filename);
403 error("%s", &parg);
404 free(parg.p_string);
373 goto err1;
405 goto err1;
406 } else
407 {
408 chflags |= CH_CANSEEK;
409 if (!force_open && !opened(ifile) && bin_file(f))
410 {
411 /*
412 * Looks like a binary file.
413 * Ask user if we should proceed.
414 */
415 parg.p_string = filename;
416 answer = query("\"%s\" may be a binary file. See it anyway? ",
417 &parg);
418 if (answer != 'y' && answer != 'Y')
419 {
420 close(f);
421 goto err1;
422 }
374 }
375 }
376 }
377
378 /*
379 * Get the new ifile.
380 * Get the saved position for the file.
381 */
382 if (was_curr_ifile != NULL_IFILE)
383 {
384 old_ifile = was_curr_ifile;
385 unsave_ifile(was_curr_ifile);
386 }
387 curr_ifile = ifile;
423 }
424 }
425 }
426
427 /*
428 * Get the new ifile.
429 * Get the saved position for the file.
430 */
431 if (was_curr_ifile != NULL_IFILE)
432 {
433 old_ifile = was_curr_ifile;
434 unsave_ifile(was_curr_ifile);
435 }
436 curr_ifile = ifile;
388 curr_altfilename = alt_filename;
389 curr_altpipe = alt_pipe;
437 set_altfilename(curr_ifile, alt_filename);
438 set_altpipe(curr_ifile, altpipe);
390 set_open(curr_ifile); /* File has been opened */
391 get_pos(curr_ifile, &initial_scrpos);
392 new_file = TRUE;
393 ch_init(f, chflags);
394
395 if (!(chflags & CH_HELPFILE))
396 {
397#if LOGFILE
398 if (namelogfile != NULL && is_tty)
399 use_logfile(namelogfile);
400#endif
401#if HAVE_STAT_INO
402 /* Remember the i-number and device of the opened file. */
439 set_open(curr_ifile); /* File has been opened */
440 get_pos(curr_ifile, &initial_scrpos);
441 new_file = TRUE;
442 ch_init(f, chflags);
443
444 if (!(chflags & CH_HELPFILE))
445 {
446#if LOGFILE
447 if (namelogfile != NULL && is_tty)
448 use_logfile(namelogfile);
449#endif
450#if HAVE_STAT_INO
451 /* Remember the i-number and device of the opened file. */
452 if (strcmp(open_filename, "-") != 0)
403 {
404 struct stat statbuf;
453 {
454 struct stat statbuf;
405 int r = stat(qopen_filename, &statbuf);
455 int r = stat(open_filename, &statbuf);
406 if (r == 0)
407 {
408 curr_ino = statbuf.st_ino;
409 curr_dev = statbuf.st_dev;
410 }
411 }
412#endif
413 if (every_first_cmd != NULL)
414 {
415 ungetcc(CHAR_END_COMMAND);
416 ungetsc(every_first_cmd);
417 }
418 }
419
456 if (r == 0)
457 {
458 curr_ino = statbuf.st_ino;
459 curr_dev = statbuf.st_dev;
460 }
461 }
462#endif
463 if (every_first_cmd != NULL)
464 {
465 ungetcc(CHAR_END_COMMAND);
466 ungetsc(every_first_cmd);
467 }
468 }
469
420 free(qopen_filename);
421 no_display = !any_display;
422 flush();
423 any_display = TRUE;
424
425 if (is_tty)
426 {
427 /*
428 * Output is to a real tty.

--- 34 unchanged lines hidden (view full) ---

463edit_list(filelist)
464 char *filelist;
465{
466 IFILE save_ifile;
467 char *good_filename;
468 char *filename;
469 char *gfilelist;
470 char *gfilename;
470 no_display = !any_display;
471 flush();
472 any_display = TRUE;
473
474 if (is_tty)
475 {
476 /*
477 * Output is to a real tty.

--- 34 unchanged lines hidden (view full) ---

512edit_list(filelist)
513 char *filelist;
514{
515 IFILE save_ifile;
516 char *good_filename;
517 char *filename;
518 char *gfilelist;
519 char *gfilename;
520 char *qfilename;
471 struct textlist tl_files;
472 struct textlist tl_gfiles;
473
474 save_ifile = save_curr_ifile();
475 good_filename = NULL;
476
477 /*
478 * Run thru each filename in the list.

--- 5 unchanged lines hidden (view full) ---

484 filename = NULL;
485 while ((filename = forw_textlist(&tl_files, filename)) != NULL)
486 {
487 gfilelist = lglob(filename);
488 init_textlist(&tl_gfiles, gfilelist);
489 gfilename = NULL;
490 while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
491 {
521 struct textlist tl_files;
522 struct textlist tl_gfiles;
523
524 save_ifile = save_curr_ifile();
525 good_filename = NULL;
526
527 /*
528 * Run thru each filename in the list.

--- 5 unchanged lines hidden (view full) ---

534 filename = NULL;
535 while ((filename = forw_textlist(&tl_files, filename)) != NULL)
536 {
537 gfilelist = lglob(filename);
538 init_textlist(&tl_gfiles, gfilelist);
539 gfilename = NULL;
540 while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
541 {
492 if (edit(gfilename) == 0 && good_filename == NULL)
542 qfilename = shell_unquote(gfilename);
543 if (edit(qfilename) == 0 && good_filename == NULL)
493 good_filename = get_filename(curr_ifile);
544 good_filename = get_filename(curr_ifile);
545 free(qfilename);
494 }
495 free(gfilelist);
496 }
497 /*
498 * Edit the first valid filename in the list.
499 */
500 if (good_filename == NULL)
501 {

--- 240 unchanged lines hidden (view full) ---

742 /*
743 * Can't currently use a log file on a file that can seek.
744 */
745 return;
746
747 /*
748 * {{ We could use access() here. }}
749 */
546 }
547 free(gfilelist);
548 }
549 /*
550 * Edit the first valid filename in the list.
551 */
552 if (good_filename == NULL)
553 {

--- 240 unchanged lines hidden (view full) ---

794 /*
795 * Can't currently use a log file on a file that can seek.
796 */
797 return;
798
799 /*
800 * {{ We could use access() here. }}
801 */
750 filename = shell_unquote(filename);
751 exists = open(filename, OPEN_READ);
752 if (exists >= 0)
753 close(exists);
754 exists = (exists >= 0);
755
756 /*
757 * Decide whether to overwrite the log file or append to it.
758 * If it doesn't exist we "overwrite" it.

--- 52 unchanged lines hidden (view full) ---

811
812 if (logfile < 0)
813 {
814 /*
815 * Error in opening logfile.
816 */
817 parg.p_string = filename;
818 error("Cannot write to \"%s\"", &parg);
802 exists = open(filename, OPEN_READ);
803 if (exists >= 0)
804 close(exists);
805 exists = (exists >= 0);
806
807 /*
808 * Decide whether to overwrite the log file or append to it.
809 * If it doesn't exist we "overwrite" it.

--- 52 unchanged lines hidden (view full) ---

862
863 if (logfile < 0)
864 {
865 /*
866 * Error in opening logfile.
867 */
868 parg.p_string = filename;
869 error("Cannot write to \"%s\"", &parg);
819 free(filename);
820 return;
821 }
870 return;
871 }
822 free(filename);
823 SET_BINARY(logfile);
824}
825
826#endif
872 SET_BINARY(logfile);
873}
874
875#endif