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 |