1a5f0fb15SPaul Saab /* 27f074f9cSXin LI * Copyright (C) 1984-2007 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 7a5f0fb15SPaul Saab * For more information about less, or for information on how to 8a5f0fb15SPaul Saab * contact the author, see the README file. 9a5f0fb15SPaul Saab */ 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab 12a5f0fb15SPaul Saab #include "less.h" 13464501a8SXin LI #if HAVE_STAT 14464501a8SXin LI #include <sys/stat.h> 15464501a8SXin LI #endif 16a5f0fb15SPaul Saab 17a5f0fb15SPaul Saab public int fd0 = 0; 18a5f0fb15SPaul Saab 19a5f0fb15SPaul Saab extern int new_file; 20a5f0fb15SPaul Saab extern int errmsgs; 21a5f0fb15SPaul Saab extern int cbufs; 22a5f0fb15SPaul Saab extern char *every_first_cmd; 23a5f0fb15SPaul Saab extern int any_display; 24a5f0fb15SPaul Saab extern int force_open; 25a5f0fb15SPaul Saab extern int is_tty; 26a5f0fb15SPaul Saab extern int sigs; 27a5f0fb15SPaul Saab extern IFILE curr_ifile; 28a5f0fb15SPaul Saab extern IFILE old_ifile; 29a5f0fb15SPaul Saab extern struct scrpos initial_scrpos; 30a5f0fb15SPaul Saab extern void constant *ml_examine; 31a5f0fb15SPaul Saab #if SPACES_IN_FILENAMES 32a5f0fb15SPaul Saab extern char openquote; 33a5f0fb15SPaul Saab extern char closequote; 34a5f0fb15SPaul Saab #endif 35a5f0fb15SPaul Saab 36a5f0fb15SPaul Saab #if LOGFILE 37a5f0fb15SPaul Saab extern int logfile; 38a5f0fb15SPaul Saab extern int force_logfile; 39a5f0fb15SPaul Saab extern char *namelogfile; 40a5f0fb15SPaul Saab #endif 41a5f0fb15SPaul Saab 42464501a8SXin LI #if HAVE_STAT_INO 43464501a8SXin LI public dev_t curr_dev; 44464501a8SXin LI public ino_t curr_ino; 45464501a8SXin LI #endif 46464501a8SXin LI 47a5f0fb15SPaul Saab char *curr_altfilename = NULL; 48a5f0fb15SPaul Saab static void *curr_altpipe; 49a5f0fb15SPaul Saab 50a5f0fb15SPaul Saab 51a5f0fb15SPaul Saab /* 52a5f0fb15SPaul Saab * Textlist functions deal with a list of words separated by spaces. 53a5f0fb15SPaul Saab * init_textlist sets up a textlist structure. 54a5f0fb15SPaul Saab * forw_textlist uses that structure to iterate thru the list of 55a5f0fb15SPaul Saab * words, returning each one as a standard null-terminated string. 56a5f0fb15SPaul Saab * back_textlist does the same, but runs thru the list backwards. 57a5f0fb15SPaul Saab */ 58a5f0fb15SPaul Saab public void 59a5f0fb15SPaul Saab init_textlist(tlist, str) 60a5f0fb15SPaul Saab struct textlist *tlist; 61a5f0fb15SPaul Saab char *str; 62a5f0fb15SPaul Saab { 63a5f0fb15SPaul Saab char *s; 64a5f0fb15SPaul Saab #if SPACES_IN_FILENAMES 65000ba3e8STim J. Robbins int meta_quoted = 0; 66000ba3e8STim J. Robbins int delim_quoted = 0; 67000ba3e8STim J. Robbins char *esc = get_meta_escape(); 68000ba3e8STim J. Robbins int esclen = strlen(esc); 69a5f0fb15SPaul Saab #endif 70a5f0fb15SPaul Saab 71a5f0fb15SPaul Saab tlist->string = skipsp(str); 72a5f0fb15SPaul Saab tlist->endstring = tlist->string + strlen(tlist->string); 73a5f0fb15SPaul Saab for (s = str; s < tlist->endstring; s++) 74a5f0fb15SPaul Saab { 75a5f0fb15SPaul Saab #if SPACES_IN_FILENAMES 76000ba3e8STim J. Robbins if (meta_quoted) 77000ba3e8STim J. Robbins { 78000ba3e8STim J. Robbins meta_quoted = 0; 79000ba3e8STim J. Robbins } else if (esclen > 0 && s + esclen < tlist->endstring && 80000ba3e8STim J. Robbins strncmp(s, esc, esclen) == 0) 81000ba3e8STim J. Robbins { 82000ba3e8STim J. Robbins meta_quoted = 1; 83000ba3e8STim J. Robbins s += esclen - 1; 84000ba3e8STim J. Robbins } else if (delim_quoted) 85000ba3e8STim J. Robbins { 86000ba3e8STim J. Robbins if (*s == closequote) 87000ba3e8STim J. Robbins delim_quoted = 0; 88000ba3e8STim J. Robbins } else /* (!delim_quoted) */ 89000ba3e8STim J. Robbins { 90000ba3e8STim J. Robbins if (*s == openquote) 91000ba3e8STim J. Robbins delim_quoted = 1; 92000ba3e8STim J. Robbins else if (*s == ' ') 93a5f0fb15SPaul Saab *s = '\0'; 94000ba3e8STim J. Robbins } 95a5f0fb15SPaul Saab #else 96a5f0fb15SPaul Saab if (*s == ' ') 97a5f0fb15SPaul Saab *s = '\0'; 98a5f0fb15SPaul Saab #endif 99a5f0fb15SPaul Saab } 100a5f0fb15SPaul Saab } 101a5f0fb15SPaul Saab 102a5f0fb15SPaul Saab public char * 103a5f0fb15SPaul Saab forw_textlist(tlist, prev) 104a5f0fb15SPaul Saab struct textlist *tlist; 105a5f0fb15SPaul Saab char *prev; 106a5f0fb15SPaul Saab { 107a5f0fb15SPaul Saab char *s; 108a5f0fb15SPaul Saab 109a5f0fb15SPaul Saab /* 110a5f0fb15SPaul Saab * prev == NULL means return the first word in the list. 111a5f0fb15SPaul Saab * Otherwise, return the word after "prev". 112a5f0fb15SPaul Saab */ 113a5f0fb15SPaul Saab if (prev == NULL) 114a5f0fb15SPaul Saab s = tlist->string; 115a5f0fb15SPaul Saab else 116a5f0fb15SPaul Saab s = prev + strlen(prev); 117a5f0fb15SPaul Saab if (s >= tlist->endstring) 118a5f0fb15SPaul Saab return (NULL); 119a5f0fb15SPaul Saab while (*s == '\0') 120a5f0fb15SPaul Saab s++; 121a5f0fb15SPaul Saab if (s >= tlist->endstring) 122a5f0fb15SPaul Saab return (NULL); 123a5f0fb15SPaul Saab return (s); 124a5f0fb15SPaul Saab } 125a5f0fb15SPaul Saab 126a5f0fb15SPaul Saab public char * 127a5f0fb15SPaul Saab back_textlist(tlist, prev) 128a5f0fb15SPaul Saab struct textlist *tlist; 129a5f0fb15SPaul Saab char *prev; 130a5f0fb15SPaul Saab { 131a5f0fb15SPaul Saab char *s; 132a5f0fb15SPaul Saab 133a5f0fb15SPaul Saab /* 134a5f0fb15SPaul Saab * prev == NULL means return the last word in the list. 135a5f0fb15SPaul Saab * Otherwise, return the word before "prev". 136a5f0fb15SPaul Saab */ 137a5f0fb15SPaul Saab if (prev == NULL) 138a5f0fb15SPaul Saab s = tlist->endstring; 139a5f0fb15SPaul Saab else if (prev <= tlist->string) 140a5f0fb15SPaul Saab return (NULL); 141a5f0fb15SPaul Saab else 142a5f0fb15SPaul Saab s = prev - 1; 143a5f0fb15SPaul Saab while (*s == '\0') 144a5f0fb15SPaul Saab s--; 145a5f0fb15SPaul Saab if (s <= tlist->string) 146a5f0fb15SPaul Saab return (NULL); 147a5f0fb15SPaul Saab while (s[-1] != '\0' && s > tlist->string) 148a5f0fb15SPaul Saab s--; 149a5f0fb15SPaul Saab return (s); 150a5f0fb15SPaul Saab } 151a5f0fb15SPaul Saab 152a5f0fb15SPaul Saab /* 153a5f0fb15SPaul Saab * Close the current input file. 154a5f0fb15SPaul Saab */ 155a5f0fb15SPaul Saab static void 156a5f0fb15SPaul Saab close_file() 157a5f0fb15SPaul Saab { 158a5f0fb15SPaul Saab struct scrpos scrpos; 159a5f0fb15SPaul Saab 160a5f0fb15SPaul Saab if (curr_ifile == NULL_IFILE) 161a5f0fb15SPaul Saab return; 162a5f0fb15SPaul Saab 163a5f0fb15SPaul Saab /* 164a5f0fb15SPaul Saab * Save the current position so that we can return to 165a5f0fb15SPaul Saab * the same position if we edit this file again. 166a5f0fb15SPaul Saab */ 167a5f0fb15SPaul Saab get_scrpos(&scrpos); 168a5f0fb15SPaul Saab if (scrpos.pos != NULL_POSITION) 169a5f0fb15SPaul Saab { 170a5f0fb15SPaul Saab store_pos(curr_ifile, &scrpos); 171a5f0fb15SPaul Saab lastmark(); 172a5f0fb15SPaul Saab } 173a5f0fb15SPaul Saab /* 174a5f0fb15SPaul Saab * Close the file descriptor, unless it is a pipe. 175a5f0fb15SPaul Saab */ 176a5f0fb15SPaul Saab ch_close(); 177a5f0fb15SPaul Saab /* 178a5f0fb15SPaul Saab * If we opened a file using an alternate name, 179a5f0fb15SPaul Saab * do special stuff to close it. 180a5f0fb15SPaul Saab */ 181a5f0fb15SPaul Saab if (curr_altfilename != NULL) 182a5f0fb15SPaul Saab { 183000ba3e8STim J. Robbins close_altfile(curr_altfilename, get_filename(curr_ifile), 184000ba3e8STim J. Robbins curr_altpipe); 185a5f0fb15SPaul Saab free(curr_altfilename); 186a5f0fb15SPaul Saab curr_altfilename = NULL; 187a5f0fb15SPaul Saab } 188a5f0fb15SPaul Saab curr_ifile = NULL_IFILE; 189464501a8SXin LI #if HAVE_STAT_INO 190464501a8SXin LI curr_ino = curr_dev = 0; 191464501a8SXin LI #endif 192a5f0fb15SPaul Saab } 193a5f0fb15SPaul Saab 194a5f0fb15SPaul Saab /* 195a5f0fb15SPaul Saab * Edit a new file (given its name). 196a5f0fb15SPaul Saab * Filename == "-" means standard input. 197a5f0fb15SPaul Saab * Filename == NULL means just close the current file. 198a5f0fb15SPaul Saab */ 199a5f0fb15SPaul Saab public int 200a5f0fb15SPaul Saab edit(filename) 201a5f0fb15SPaul Saab char *filename; 202a5f0fb15SPaul Saab { 203a5f0fb15SPaul Saab if (filename == NULL) 204a5f0fb15SPaul Saab return (edit_ifile(NULL_IFILE)); 205a5f0fb15SPaul Saab return (edit_ifile(get_ifile(filename, curr_ifile))); 206a5f0fb15SPaul Saab } 207a5f0fb15SPaul Saab 208a5f0fb15SPaul Saab /* 209a5f0fb15SPaul Saab * Edit a new file (given its IFILE). 210a5f0fb15SPaul Saab * ifile == NULL means just close the current file. 211a5f0fb15SPaul Saab */ 212a5f0fb15SPaul Saab public int 213a5f0fb15SPaul Saab edit_ifile(ifile) 214a5f0fb15SPaul Saab IFILE ifile; 215a5f0fb15SPaul Saab { 216a5f0fb15SPaul Saab int f; 217a5f0fb15SPaul Saab int answer; 218a5f0fb15SPaul Saab int no_display; 219a5f0fb15SPaul Saab int chflags; 220a5f0fb15SPaul Saab char *filename; 221a5f0fb15SPaul Saab char *open_filename; 222000ba3e8STim J. Robbins char *qopen_filename; 223a5f0fb15SPaul Saab char *alt_filename; 224a5f0fb15SPaul Saab void *alt_pipe; 225a5f0fb15SPaul Saab IFILE was_curr_ifile; 226a5f0fb15SPaul Saab PARG parg; 227a5f0fb15SPaul Saab 228a5f0fb15SPaul Saab if (ifile == curr_ifile) 229a5f0fb15SPaul Saab { 230a5f0fb15SPaul Saab /* 231a5f0fb15SPaul Saab * Already have the correct file open. 232a5f0fb15SPaul Saab */ 233a5f0fb15SPaul Saab return (0); 234a5f0fb15SPaul Saab } 235a5f0fb15SPaul Saab 236a5f0fb15SPaul Saab /* 237a5f0fb15SPaul Saab * We must close the currently open file now. 238a5f0fb15SPaul Saab * This is necessary to make the open_altfile/close_altfile pairs 239a5f0fb15SPaul Saab * nest properly (or rather to avoid nesting at all). 240a5f0fb15SPaul Saab * {{ Some stupid implementations of popen() mess up if you do: 241a5f0fb15SPaul Saab * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }} 242a5f0fb15SPaul Saab */ 243a5f0fb15SPaul Saab #if LOGFILE 244a5f0fb15SPaul Saab end_logfile(); 245a5f0fb15SPaul Saab #endif 246a5f0fb15SPaul Saab was_curr_ifile = save_curr_ifile(); 247a5f0fb15SPaul Saab if (curr_ifile != NULL_IFILE) 248a5f0fb15SPaul Saab { 249a5f0fb15SPaul Saab chflags = ch_getflags(); 250a5f0fb15SPaul Saab close_file(); 251a5f0fb15SPaul Saab if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1) 252a5f0fb15SPaul Saab { 253a5f0fb15SPaul Saab /* 254a5f0fb15SPaul Saab * Don't keep the help file in the ifile list. 255a5f0fb15SPaul Saab */ 256a5f0fb15SPaul Saab del_ifile(was_curr_ifile); 257a5f0fb15SPaul Saab was_curr_ifile = old_ifile; 258a5f0fb15SPaul Saab } 259a5f0fb15SPaul Saab } 260a5f0fb15SPaul Saab 261a5f0fb15SPaul Saab if (ifile == NULL_IFILE) 262a5f0fb15SPaul Saab { 263a5f0fb15SPaul Saab /* 264a5f0fb15SPaul Saab * No new file to open. 265a5f0fb15SPaul Saab * (Don't set old_ifile, because if you call edit_ifile(NULL), 266a5f0fb15SPaul Saab * you're supposed to have saved curr_ifile yourself, 267a5f0fb15SPaul Saab * and you'll restore it if necessary.) 268a5f0fb15SPaul Saab */ 269a5f0fb15SPaul Saab unsave_ifile(was_curr_ifile); 270a5f0fb15SPaul Saab return (0); 271a5f0fb15SPaul Saab } 272a5f0fb15SPaul Saab 273000ba3e8STim J. Robbins filename = save(get_filename(ifile)); 274a5f0fb15SPaul Saab /* 275a5f0fb15SPaul Saab * See if LESSOPEN specifies an "alternate" file to open. 276a5f0fb15SPaul Saab */ 277a5f0fb15SPaul Saab alt_pipe = NULL; 278a5f0fb15SPaul Saab alt_filename = open_altfile(filename, &f, &alt_pipe); 279a5f0fb15SPaul Saab open_filename = (alt_filename != NULL) ? alt_filename : filename; 280000ba3e8STim J. Robbins qopen_filename = shell_unquote(open_filename); 281a5f0fb15SPaul Saab 282a5f0fb15SPaul Saab chflags = 0; 283a5f0fb15SPaul Saab if (alt_pipe != NULL) 284a5f0fb15SPaul Saab { 285a5f0fb15SPaul Saab /* 286a5f0fb15SPaul Saab * The alternate "file" is actually a pipe. 287a5f0fb15SPaul Saab * f has already been set to the file descriptor of the pipe 288a5f0fb15SPaul Saab * in the call to open_altfile above. 289a5f0fb15SPaul Saab * Keep the file descriptor open because it was opened 290a5f0fb15SPaul Saab * via popen(), and pclose() wants to close it. 291a5f0fb15SPaul Saab */ 292a5f0fb15SPaul Saab chflags |= CH_POPENED; 293a5f0fb15SPaul Saab } else if (strcmp(open_filename, "-") == 0) 294a5f0fb15SPaul Saab { 295a5f0fb15SPaul Saab /* 296a5f0fb15SPaul Saab * Use standard input. 297a5f0fb15SPaul Saab * Keep the file descriptor open because we can't reopen it. 298a5f0fb15SPaul Saab */ 299a5f0fb15SPaul Saab f = fd0; 300a5f0fb15SPaul Saab chflags |= CH_KEEPOPEN; 301a5f0fb15SPaul Saab /* 302a5f0fb15SPaul Saab * Must switch stdin to BINARY mode. 303a5f0fb15SPaul Saab */ 304a5f0fb15SPaul Saab SET_BINARY(f); 305a5f0fb15SPaul Saab #if MSDOS_COMPILER==DJGPPC 306a5f0fb15SPaul Saab /* 307a5f0fb15SPaul Saab * Setting stdin to binary by default causes 308a5f0fb15SPaul Saab * Ctrl-C to not raise SIGINT. We must undo 309a5f0fb15SPaul Saab * that side-effect. 310a5f0fb15SPaul Saab */ 311a5f0fb15SPaul Saab __djgpp_set_ctrl_c(1); 312a5f0fb15SPaul Saab #endif 313a5f0fb15SPaul Saab } else if (strcmp(open_filename, FAKE_HELPFILE) == 0) 314a5f0fb15SPaul Saab { 315a5f0fb15SPaul Saab f = -1; 316a5f0fb15SPaul Saab chflags |= CH_HELPFILE; 317a5f0fb15SPaul Saab } else if ((parg.p_string = bad_file(open_filename)) != NULL) 318a5f0fb15SPaul Saab { 319a5f0fb15SPaul Saab /* 320a5f0fb15SPaul Saab * It looks like a bad file. Don't try to open it. 321a5f0fb15SPaul Saab */ 322a5f0fb15SPaul Saab error("%s", &parg); 323a5f0fb15SPaul Saab free(parg.p_string); 324a5f0fb15SPaul Saab err1: 325a5f0fb15SPaul Saab if (alt_filename != NULL) 326a5f0fb15SPaul Saab { 327a5f0fb15SPaul Saab close_altfile(alt_filename, filename, alt_pipe); 328a5f0fb15SPaul Saab free(alt_filename); 329a5f0fb15SPaul Saab } 330a5f0fb15SPaul Saab del_ifile(ifile); 331000ba3e8STim J. Robbins free(qopen_filename); 332a5f0fb15SPaul Saab free(filename); 333a5f0fb15SPaul Saab /* 334a5f0fb15SPaul Saab * Re-open the current file. 335a5f0fb15SPaul Saab */ 3366dcb072bSXin LI if (was_curr_ifile == ifile) 3376dcb072bSXin LI { 3386dcb072bSXin LI /* 3396dcb072bSXin LI * Whoops. The "current" ifile is the one we just deleted. 3406dcb072bSXin LI * Just give up. 3416dcb072bSXin LI */ 3426dcb072bSXin LI quit(QUIT_ERROR); 3436dcb072bSXin LI } 344a5f0fb15SPaul Saab reedit_ifile(was_curr_ifile); 345a5f0fb15SPaul Saab return (1); 346000ba3e8STim J. Robbins } else if ((f = open(qopen_filename, OPEN_READ)) < 0) 347a5f0fb15SPaul Saab { 348a5f0fb15SPaul Saab /* 349a5f0fb15SPaul Saab * Got an error trying to open it. 350a5f0fb15SPaul Saab */ 351a5f0fb15SPaul Saab parg.p_string = errno_message(filename); 352a5f0fb15SPaul Saab error("%s", &parg); 353a5f0fb15SPaul Saab free(parg.p_string); 354a5f0fb15SPaul Saab goto err1; 355a5f0fb15SPaul Saab } else 356a5f0fb15SPaul Saab { 357a5f0fb15SPaul Saab chflags |= CH_CANSEEK; 358a5f0fb15SPaul Saab if (!force_open && !opened(ifile) && bin_file(f)) 359a5f0fb15SPaul Saab { 360a5f0fb15SPaul Saab /* 361a5f0fb15SPaul Saab * Looks like a binary file. 362a5f0fb15SPaul Saab * Ask user if we should proceed. 363a5f0fb15SPaul Saab */ 364a5f0fb15SPaul Saab parg.p_string = filename; 365a5f0fb15SPaul Saab answer = query("\"%s\" may be a binary file. See it anyway? ", 366a5f0fb15SPaul Saab &parg); 367a5f0fb15SPaul Saab if (answer != 'y' && answer != 'Y') 368a5f0fb15SPaul Saab { 369a5f0fb15SPaul Saab close(f); 370a5f0fb15SPaul Saab goto err1; 371a5f0fb15SPaul Saab } 372a5f0fb15SPaul Saab } 373a5f0fb15SPaul Saab } 374a5f0fb15SPaul Saab 375a5f0fb15SPaul Saab /* 376a5f0fb15SPaul Saab * Get the new ifile. 377a5f0fb15SPaul Saab * Get the saved position for the file. 378a5f0fb15SPaul Saab */ 379a5f0fb15SPaul Saab if (was_curr_ifile != NULL_IFILE) 380a5f0fb15SPaul Saab { 381a5f0fb15SPaul Saab old_ifile = was_curr_ifile; 382a5f0fb15SPaul Saab unsave_ifile(was_curr_ifile); 383a5f0fb15SPaul Saab } 384a5f0fb15SPaul Saab curr_ifile = ifile; 385a5f0fb15SPaul Saab curr_altfilename = alt_filename; 386a5f0fb15SPaul Saab curr_altpipe = alt_pipe; 387a5f0fb15SPaul Saab set_open(curr_ifile); /* File has been opened */ 388a5f0fb15SPaul Saab get_pos(curr_ifile, &initial_scrpos); 389a5f0fb15SPaul Saab new_file = TRUE; 390a5f0fb15SPaul Saab ch_init(f, chflags); 391a5f0fb15SPaul Saab 392a5f0fb15SPaul Saab if (!(chflags & CH_HELPFILE)) 393a5f0fb15SPaul Saab { 394a5f0fb15SPaul Saab #if LOGFILE 395a5f0fb15SPaul Saab if (namelogfile != NULL && is_tty) 396a5f0fb15SPaul Saab use_logfile(namelogfile); 397a5f0fb15SPaul Saab #endif 398464501a8SXin LI #if HAVE_STAT_INO 399464501a8SXin LI /* Remember the i-number and device of the opened file. */ 400464501a8SXin LI { 401464501a8SXin LI struct stat statbuf; 402464501a8SXin LI int r = stat(qopen_filename, &statbuf); 403464501a8SXin LI if (r == 0) 404464501a8SXin LI { 405464501a8SXin LI curr_ino = statbuf.st_ino; 406464501a8SXin LI curr_dev = statbuf.st_dev; 407464501a8SXin LI } 408464501a8SXin LI } 409464501a8SXin LI #endif 410a5f0fb15SPaul Saab if (every_first_cmd != NULL) 411a5f0fb15SPaul Saab ungetsc(every_first_cmd); 412a5f0fb15SPaul Saab } 413a5f0fb15SPaul Saab 414464501a8SXin LI free(qopen_filename); 415a5f0fb15SPaul Saab no_display = !any_display; 416a5f0fb15SPaul Saab flush(); 417a5f0fb15SPaul Saab any_display = TRUE; 418a5f0fb15SPaul Saab 419a5f0fb15SPaul Saab if (is_tty) 420a5f0fb15SPaul Saab { 421a5f0fb15SPaul Saab /* 422a5f0fb15SPaul Saab * Output is to a real tty. 423a5f0fb15SPaul Saab */ 424a5f0fb15SPaul Saab 425a5f0fb15SPaul Saab /* 426a5f0fb15SPaul Saab * Indicate there is nothing displayed yet. 427a5f0fb15SPaul Saab */ 428a5f0fb15SPaul Saab pos_clear(); 429a5f0fb15SPaul Saab clr_linenum(); 430a5f0fb15SPaul Saab #if HILITE_SEARCH 431a5f0fb15SPaul Saab clr_hilite(); 432a5f0fb15SPaul Saab #endif 433a5f0fb15SPaul Saab cmd_addhist(ml_examine, filename); 434a5f0fb15SPaul Saab if (no_display && errmsgs > 0) 435a5f0fb15SPaul Saab { 436a5f0fb15SPaul Saab /* 437a5f0fb15SPaul Saab * We displayed some messages on error output 438a5f0fb15SPaul Saab * (file descriptor 2; see error() function). 439a5f0fb15SPaul Saab * Before erasing the screen contents, 440a5f0fb15SPaul Saab * display the file name and wait for a keystroke. 441a5f0fb15SPaul Saab */ 442a5f0fb15SPaul Saab parg.p_string = filename; 443a5f0fb15SPaul Saab error("%s", &parg); 444a5f0fb15SPaul Saab } 445a5f0fb15SPaul Saab } 446a5f0fb15SPaul Saab free(filename); 447a5f0fb15SPaul Saab return (0); 448a5f0fb15SPaul Saab } 449a5f0fb15SPaul Saab 450a5f0fb15SPaul Saab /* 451a5f0fb15SPaul Saab * Edit a space-separated list of files. 452a5f0fb15SPaul Saab * For each filename in the list, enter it into the ifile list. 453a5f0fb15SPaul Saab * Then edit the first one. 454a5f0fb15SPaul Saab */ 455a5f0fb15SPaul Saab public int 456a5f0fb15SPaul Saab edit_list(filelist) 457a5f0fb15SPaul Saab char *filelist; 458a5f0fb15SPaul Saab { 459a5f0fb15SPaul Saab IFILE save_ifile; 460a5f0fb15SPaul Saab char *good_filename; 461a5f0fb15SPaul Saab char *filename; 462a5f0fb15SPaul Saab char *gfilelist; 463a5f0fb15SPaul Saab char *gfilename; 464a5f0fb15SPaul Saab struct textlist tl_files; 465a5f0fb15SPaul Saab struct textlist tl_gfiles; 466a5f0fb15SPaul Saab 467a5f0fb15SPaul Saab save_ifile = save_curr_ifile(); 468a5f0fb15SPaul Saab good_filename = NULL; 469a5f0fb15SPaul Saab 470a5f0fb15SPaul Saab /* 471a5f0fb15SPaul Saab * Run thru each filename in the list. 472a5f0fb15SPaul Saab * Try to glob the filename. 473a5f0fb15SPaul Saab * If it doesn't expand, just try to open the filename. 474a5f0fb15SPaul Saab * If it does expand, try to open each name in that list. 475a5f0fb15SPaul Saab */ 476a5f0fb15SPaul Saab init_textlist(&tl_files, filelist); 477a5f0fb15SPaul Saab filename = NULL; 478a5f0fb15SPaul Saab while ((filename = forw_textlist(&tl_files, filename)) != NULL) 479a5f0fb15SPaul Saab { 480a5f0fb15SPaul Saab gfilelist = lglob(filename); 481a5f0fb15SPaul Saab init_textlist(&tl_gfiles, gfilelist); 482a5f0fb15SPaul Saab gfilename = NULL; 483a5f0fb15SPaul Saab while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL) 484a5f0fb15SPaul Saab { 485a5f0fb15SPaul Saab if (edit(gfilename) == 0 && good_filename == NULL) 486a5f0fb15SPaul Saab good_filename = get_filename(curr_ifile); 487a5f0fb15SPaul Saab } 488a5f0fb15SPaul Saab free(gfilelist); 489a5f0fb15SPaul Saab } 490a5f0fb15SPaul Saab /* 491a5f0fb15SPaul Saab * Edit the first valid filename in the list. 492a5f0fb15SPaul Saab */ 493a5f0fb15SPaul Saab if (good_filename == NULL) 494a5f0fb15SPaul Saab { 495a5f0fb15SPaul Saab unsave_ifile(save_ifile); 496a5f0fb15SPaul Saab return (1); 497a5f0fb15SPaul Saab } 498a5f0fb15SPaul Saab if (get_ifile(good_filename, curr_ifile) == curr_ifile) 499a5f0fb15SPaul Saab { 500a5f0fb15SPaul Saab /* 501a5f0fb15SPaul Saab * Trying to edit the current file; don't reopen it. 502a5f0fb15SPaul Saab */ 503a5f0fb15SPaul Saab unsave_ifile(save_ifile); 504a5f0fb15SPaul Saab return (0); 505a5f0fb15SPaul Saab } 506a5f0fb15SPaul Saab reedit_ifile(save_ifile); 507a5f0fb15SPaul Saab return (edit(good_filename)); 508a5f0fb15SPaul Saab } 509a5f0fb15SPaul Saab 510a5f0fb15SPaul Saab /* 511a5f0fb15SPaul Saab * Edit the first file in the command line (ifile) list. 512a5f0fb15SPaul Saab */ 513a5f0fb15SPaul Saab public int 514a5f0fb15SPaul Saab edit_first() 515a5f0fb15SPaul Saab { 516a5f0fb15SPaul Saab curr_ifile = NULL_IFILE; 517a5f0fb15SPaul Saab return (edit_next(1)); 518a5f0fb15SPaul Saab } 519a5f0fb15SPaul Saab 520a5f0fb15SPaul Saab /* 521a5f0fb15SPaul Saab * Edit the last file in the command line (ifile) list. 522a5f0fb15SPaul Saab */ 523a5f0fb15SPaul Saab public int 524a5f0fb15SPaul Saab edit_last() 525a5f0fb15SPaul Saab { 526a5f0fb15SPaul Saab curr_ifile = NULL_IFILE; 527a5f0fb15SPaul Saab return (edit_prev(1)); 528a5f0fb15SPaul Saab } 529a5f0fb15SPaul Saab 530a5f0fb15SPaul Saab 531a5f0fb15SPaul Saab /* 5326dcb072bSXin LI * Edit the n-th next or previous file in the command line (ifile) list. 533a5f0fb15SPaul Saab */ 534a5f0fb15SPaul Saab static int 535a5f0fb15SPaul Saab edit_istep(h, n, dir) 536a5f0fb15SPaul Saab IFILE h; 537a5f0fb15SPaul Saab int n; 538a5f0fb15SPaul Saab int dir; 539a5f0fb15SPaul Saab { 540a5f0fb15SPaul Saab IFILE next; 541a5f0fb15SPaul Saab 542a5f0fb15SPaul Saab /* 543a5f0fb15SPaul Saab * Skip n filenames, then try to edit each filename. 544a5f0fb15SPaul Saab */ 545a5f0fb15SPaul Saab for (;;) 546a5f0fb15SPaul Saab { 547a5f0fb15SPaul Saab next = (dir > 0) ? next_ifile(h) : prev_ifile(h); 548a5f0fb15SPaul Saab if (--n < 0) 549a5f0fb15SPaul Saab { 550a5f0fb15SPaul Saab if (edit_ifile(h) == 0) 551a5f0fb15SPaul Saab break; 552a5f0fb15SPaul Saab } 553a5f0fb15SPaul Saab if (next == NULL_IFILE) 554a5f0fb15SPaul Saab { 555a5f0fb15SPaul Saab /* 556a5f0fb15SPaul Saab * Reached end of the ifile list. 557a5f0fb15SPaul Saab */ 558a5f0fb15SPaul Saab return (1); 559a5f0fb15SPaul Saab } 560a5f0fb15SPaul Saab if (ABORT_SIGS()) 561a5f0fb15SPaul Saab { 562a5f0fb15SPaul Saab /* 563a5f0fb15SPaul Saab * Interrupt breaks out, if we're in a long 564a5f0fb15SPaul Saab * list of files that can't be opened. 565a5f0fb15SPaul Saab */ 566a5f0fb15SPaul Saab return (1); 567a5f0fb15SPaul Saab } 568a5f0fb15SPaul Saab h = next; 569a5f0fb15SPaul Saab } 570a5f0fb15SPaul Saab /* 571a5f0fb15SPaul Saab * Found a file that we can edit. 572a5f0fb15SPaul Saab */ 573a5f0fb15SPaul Saab return (0); 574a5f0fb15SPaul Saab } 575a5f0fb15SPaul Saab 576a5f0fb15SPaul Saab static int 577a5f0fb15SPaul Saab edit_inext(h, n) 578a5f0fb15SPaul Saab IFILE h; 579a5f0fb15SPaul Saab int n; 580a5f0fb15SPaul Saab { 5816dcb072bSXin LI return (edit_istep(h, n, +1)); 582a5f0fb15SPaul Saab } 583a5f0fb15SPaul Saab 584a5f0fb15SPaul Saab public int 585a5f0fb15SPaul Saab edit_next(n) 586a5f0fb15SPaul Saab int n; 587a5f0fb15SPaul Saab { 5886dcb072bSXin LI return edit_istep(curr_ifile, n, +1); 589a5f0fb15SPaul Saab } 590a5f0fb15SPaul Saab 591a5f0fb15SPaul Saab static int 592a5f0fb15SPaul Saab edit_iprev(h, n) 593a5f0fb15SPaul Saab IFILE h; 594a5f0fb15SPaul Saab int n; 595a5f0fb15SPaul Saab { 596a5f0fb15SPaul Saab return (edit_istep(h, n, -1)); 597a5f0fb15SPaul Saab } 598a5f0fb15SPaul Saab 599a5f0fb15SPaul Saab public int 600a5f0fb15SPaul Saab edit_prev(n) 601a5f0fb15SPaul Saab int n; 602a5f0fb15SPaul Saab { 603a5f0fb15SPaul Saab return edit_istep(curr_ifile, n, -1); 604a5f0fb15SPaul Saab } 605a5f0fb15SPaul Saab 606a5f0fb15SPaul Saab /* 607a5f0fb15SPaul Saab * Edit a specific file in the command line (ifile) list. 608a5f0fb15SPaul Saab */ 609a5f0fb15SPaul Saab public int 610a5f0fb15SPaul Saab edit_index(n) 611a5f0fb15SPaul Saab int n; 612a5f0fb15SPaul Saab { 613a5f0fb15SPaul Saab IFILE h; 614a5f0fb15SPaul Saab 615a5f0fb15SPaul Saab h = NULL_IFILE; 616a5f0fb15SPaul Saab do 617a5f0fb15SPaul Saab { 618a5f0fb15SPaul Saab if ((h = next_ifile(h)) == NULL_IFILE) 619a5f0fb15SPaul Saab { 620a5f0fb15SPaul Saab /* 621a5f0fb15SPaul Saab * Reached end of the list without finding it. 622a5f0fb15SPaul Saab */ 623a5f0fb15SPaul Saab return (1); 624a5f0fb15SPaul Saab } 625a5f0fb15SPaul Saab } while (get_index(h) != n); 626a5f0fb15SPaul Saab 627a5f0fb15SPaul Saab return (edit_ifile(h)); 628a5f0fb15SPaul Saab } 629a5f0fb15SPaul Saab 630a5f0fb15SPaul Saab public IFILE 631a5f0fb15SPaul Saab save_curr_ifile() 632a5f0fb15SPaul Saab { 633a5f0fb15SPaul Saab if (curr_ifile != NULL_IFILE) 634a5f0fb15SPaul Saab hold_ifile(curr_ifile, 1); 635a5f0fb15SPaul Saab return (curr_ifile); 636a5f0fb15SPaul Saab } 637a5f0fb15SPaul Saab 638a5f0fb15SPaul Saab public void 639a5f0fb15SPaul Saab unsave_ifile(save_ifile) 640a5f0fb15SPaul Saab IFILE save_ifile; 641a5f0fb15SPaul Saab { 642a5f0fb15SPaul Saab if (save_ifile != NULL_IFILE) 643a5f0fb15SPaul Saab hold_ifile(save_ifile, -1); 644a5f0fb15SPaul Saab } 645a5f0fb15SPaul Saab 646a5f0fb15SPaul Saab /* 647a5f0fb15SPaul Saab * Reedit the ifile which was previously open. 648a5f0fb15SPaul Saab */ 649a5f0fb15SPaul Saab public void 650a5f0fb15SPaul Saab reedit_ifile(save_ifile) 651a5f0fb15SPaul Saab IFILE save_ifile; 652a5f0fb15SPaul Saab { 653a5f0fb15SPaul Saab IFILE next; 654a5f0fb15SPaul Saab IFILE prev; 655a5f0fb15SPaul Saab 656a5f0fb15SPaul Saab /* 657a5f0fb15SPaul Saab * Try to reopen the ifile. 658a5f0fb15SPaul Saab * Note that opening it may fail (maybe the file was removed), 659a5f0fb15SPaul Saab * in which case the ifile will be deleted from the list. 660a5f0fb15SPaul Saab * So save the next and prev ifiles first. 661a5f0fb15SPaul Saab */ 662a5f0fb15SPaul Saab unsave_ifile(save_ifile); 663a5f0fb15SPaul Saab next = next_ifile(save_ifile); 664a5f0fb15SPaul Saab prev = prev_ifile(save_ifile); 665a5f0fb15SPaul Saab if (edit_ifile(save_ifile) == 0) 666a5f0fb15SPaul Saab return; 667a5f0fb15SPaul Saab /* 668a5f0fb15SPaul Saab * If can't reopen it, open the next input file in the list. 669a5f0fb15SPaul Saab */ 670a5f0fb15SPaul Saab if (next != NULL_IFILE && edit_inext(next, 0) == 0) 671a5f0fb15SPaul Saab return; 672a5f0fb15SPaul Saab /* 673a5f0fb15SPaul Saab * If can't open THAT one, open the previous input file in the list. 674a5f0fb15SPaul Saab */ 675a5f0fb15SPaul Saab if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0) 676a5f0fb15SPaul Saab return; 677a5f0fb15SPaul Saab /* 678a5f0fb15SPaul Saab * If can't even open that, we're stuck. Just quit. 679a5f0fb15SPaul Saab */ 680a5f0fb15SPaul Saab quit(QUIT_ERROR); 681a5f0fb15SPaul Saab } 682a5f0fb15SPaul Saab 683464501a8SXin LI public void 684464501a8SXin LI reopen_curr_ifile() 685464501a8SXin LI { 686464501a8SXin LI IFILE save_ifile = save_curr_ifile(); 687464501a8SXin LI close_file(); 688464501a8SXin LI reedit_ifile(save_ifile); 689464501a8SXin LI } 690464501a8SXin LI 691a5f0fb15SPaul Saab /* 692a5f0fb15SPaul Saab * Edit standard input. 693a5f0fb15SPaul Saab */ 694a5f0fb15SPaul Saab public int 695a5f0fb15SPaul Saab edit_stdin() 696a5f0fb15SPaul Saab { 697a5f0fb15SPaul Saab if (isatty(fd0)) 698a5f0fb15SPaul Saab { 699a5f0fb15SPaul Saab error("Missing filename (\"less --help\" for help)", NULL_PARG); 700a5f0fb15SPaul Saab quit(QUIT_OK); 701a5f0fb15SPaul Saab } 702a5f0fb15SPaul Saab return (edit("-")); 703a5f0fb15SPaul Saab } 704a5f0fb15SPaul Saab 705a5f0fb15SPaul Saab /* 706a5f0fb15SPaul Saab * Copy a file directly to standard output. 707a5f0fb15SPaul Saab * Used if standard output is not a tty. 708a5f0fb15SPaul Saab */ 709a5f0fb15SPaul Saab public void 710a5f0fb15SPaul Saab cat_file() 711a5f0fb15SPaul Saab { 712a5f0fb15SPaul Saab register int c; 713a5f0fb15SPaul Saab 714a5f0fb15SPaul Saab while ((c = ch_forw_get()) != EOI) 715a5f0fb15SPaul Saab putchr(c); 716a5f0fb15SPaul Saab flush(); 717a5f0fb15SPaul Saab } 718a5f0fb15SPaul Saab 719a5f0fb15SPaul Saab #if LOGFILE 720a5f0fb15SPaul Saab 721a5f0fb15SPaul Saab /* 722a5f0fb15SPaul Saab * If the user asked for a log file and our input file 723a5f0fb15SPaul Saab * is standard input, create the log file. 724a5f0fb15SPaul Saab * We take care not to blindly overwrite an existing file. 725a5f0fb15SPaul Saab */ 726a5f0fb15SPaul Saab public void 727a5f0fb15SPaul Saab use_logfile(filename) 728a5f0fb15SPaul Saab char *filename; 729a5f0fb15SPaul Saab { 730a5f0fb15SPaul Saab register int exists; 731a5f0fb15SPaul Saab register int answer; 732a5f0fb15SPaul Saab PARG parg; 733a5f0fb15SPaul Saab 734a5f0fb15SPaul Saab if (ch_getflags() & CH_CANSEEK) 735a5f0fb15SPaul Saab /* 736a5f0fb15SPaul Saab * Can't currently use a log file on a file that can seek. 737a5f0fb15SPaul Saab */ 738a5f0fb15SPaul Saab return; 739a5f0fb15SPaul Saab 740a5f0fb15SPaul Saab /* 741a5f0fb15SPaul Saab * {{ We could use access() here. }} 742a5f0fb15SPaul Saab */ 743000ba3e8STim J. Robbins filename = shell_unquote(filename); 744a5f0fb15SPaul Saab exists = open(filename, OPEN_READ); 745a5f0fb15SPaul Saab close(exists); 746a5f0fb15SPaul Saab exists = (exists >= 0); 747a5f0fb15SPaul Saab 748a5f0fb15SPaul Saab /* 749a5f0fb15SPaul Saab * Decide whether to overwrite the log file or append to it. 750a5f0fb15SPaul Saab * If it doesn't exist we "overwrite" it. 751a5f0fb15SPaul Saab */ 752a5f0fb15SPaul Saab if (!exists || force_logfile) 753a5f0fb15SPaul Saab { 754a5f0fb15SPaul Saab /* 755a5f0fb15SPaul Saab * Overwrite (or create) the log file. 756a5f0fb15SPaul Saab */ 757a5f0fb15SPaul Saab answer = 'O'; 758a5f0fb15SPaul Saab } else 759a5f0fb15SPaul Saab { 760a5f0fb15SPaul Saab /* 761a5f0fb15SPaul Saab * Ask user what to do. 762a5f0fb15SPaul Saab */ 763a5f0fb15SPaul Saab parg.p_string = filename; 764a5f0fb15SPaul Saab answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg); 765a5f0fb15SPaul Saab } 766a5f0fb15SPaul Saab 767a5f0fb15SPaul Saab loop: 768a5f0fb15SPaul Saab switch (answer) 769a5f0fb15SPaul Saab { 770a5f0fb15SPaul Saab case 'O': case 'o': 771a5f0fb15SPaul Saab /* 772a5f0fb15SPaul Saab * Overwrite: create the file. 773a5f0fb15SPaul Saab */ 774a5f0fb15SPaul Saab logfile = creat(filename, 0644); 775a5f0fb15SPaul Saab break; 776a5f0fb15SPaul Saab case 'A': case 'a': 777a5f0fb15SPaul Saab /* 778a5f0fb15SPaul Saab * Append: open the file and seek to the end. 779a5f0fb15SPaul Saab */ 780a5f0fb15SPaul Saab logfile = open(filename, OPEN_APPEND); 781464501a8SXin LI if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK) 782a5f0fb15SPaul Saab { 783a5f0fb15SPaul Saab close(logfile); 784a5f0fb15SPaul Saab logfile = -1; 785a5f0fb15SPaul Saab } 786a5f0fb15SPaul Saab break; 787a5f0fb15SPaul Saab case 'D': case 'd': 788a5f0fb15SPaul Saab /* 789a5f0fb15SPaul Saab * Don't do anything. 790a5f0fb15SPaul Saab */ 791a5f0fb15SPaul Saab free(filename); 792a5f0fb15SPaul Saab return; 793a5f0fb15SPaul Saab case 'q': 794a5f0fb15SPaul Saab quit(QUIT_OK); 795a5f0fb15SPaul Saab /*NOTREACHED*/ 796a5f0fb15SPaul Saab default: 797a5f0fb15SPaul Saab /* 798a5f0fb15SPaul Saab * Eh? 799a5f0fb15SPaul Saab */ 800a5f0fb15SPaul Saab answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG); 801a5f0fb15SPaul Saab goto loop; 802a5f0fb15SPaul Saab } 803a5f0fb15SPaul Saab 804a5f0fb15SPaul Saab if (logfile < 0) 805a5f0fb15SPaul Saab { 806a5f0fb15SPaul Saab /* 807a5f0fb15SPaul Saab * Error in opening logfile. 808a5f0fb15SPaul Saab */ 809a5f0fb15SPaul Saab parg.p_string = filename; 810a5f0fb15SPaul Saab error("Cannot write to \"%s\"", &parg); 811a5f0fb15SPaul Saab free(filename); 812a5f0fb15SPaul Saab return; 813a5f0fb15SPaul Saab } 814a5f0fb15SPaul Saab free(filename); 815a5f0fb15SPaul Saab SET_BINARY(logfile); 816a5f0fb15SPaul Saab } 817a5f0fb15SPaul Saab 818a5f0fb15SPaul Saab #endif 819