1b8ba871bSPeter Wemm /*- 2b8ba871bSPeter Wemm * Copyright (c) 1992, 1993, 1994 3b8ba871bSPeter Wemm * The Regents of the University of California. All rights reserved. 4b8ba871bSPeter Wemm * Copyright (c) 1992, 1993, 1994, 1995, 1996 5b8ba871bSPeter Wemm * Keith Bostic. All rights reserved. 6b8ba871bSPeter Wemm * 7b8ba871bSPeter Wemm * See the LICENSE file for redistribution information. 8b8ba871bSPeter Wemm */ 9b8ba871bSPeter Wemm 10b8ba871bSPeter Wemm #include "config.h" 11b8ba871bSPeter Wemm 12b8ba871bSPeter Wemm #ifndef lint 13b8ba871bSPeter Wemm static const char copyright[] = 14b8ba871bSPeter Wemm "@(#) Copyright (c) 1992, 1993, 1994\n\ 15b8ba871bSPeter Wemm The Regents of the University of California. All rights reserved.\n\ 16b8ba871bSPeter Wemm @(#) Copyright (c) 1992, 1993, 1994, 1995, 1996\n\ 17b8ba871bSPeter Wemm Keith Bostic. All rights reserved.\n"; 18b8ba871bSPeter Wemm #endif /* not lint */ 19b8ba871bSPeter Wemm 20b8ba871bSPeter Wemm #ifndef lint 21b8ba871bSPeter Wemm static const char sccsid[] = "@(#)main.c 10.48 (Berkeley) 10/11/96"; 22b8ba871bSPeter Wemm #endif /* not lint */ 23b8ba871bSPeter Wemm 24b8ba871bSPeter Wemm #include <sys/types.h> 25b8ba871bSPeter Wemm #include <sys/queue.h> 26b8ba871bSPeter Wemm #include <sys/stat.h> 27b8ba871bSPeter Wemm #include <sys/time.h> 28b8ba871bSPeter Wemm 29b8ba871bSPeter Wemm #include <bitstring.h> 30b8ba871bSPeter Wemm #include <errno.h> 31b8ba871bSPeter Wemm #include <fcntl.h> 32b8ba871bSPeter Wemm #include <limits.h> 33b8ba871bSPeter Wemm #include <stdio.h> 34b8ba871bSPeter Wemm #include <stdlib.h> 35b8ba871bSPeter Wemm #include <string.h> 36b8ba871bSPeter Wemm #include <unistd.h> 37b8ba871bSPeter Wemm 38b8ba871bSPeter Wemm #include "common.h" 39b8ba871bSPeter Wemm #include "../vi/vi.h" 40b8ba871bSPeter Wemm #include "pathnames.h" 41b8ba871bSPeter Wemm 42b8ba871bSPeter Wemm static void attach __P((GS *)); 43b8ba871bSPeter Wemm static void v_estr __P((char *, int, char *)); 44b8ba871bSPeter Wemm static int v_obsolete __P((char *, char *[])); 45b8ba871bSPeter Wemm 46b8ba871bSPeter Wemm /* 47b8ba871bSPeter Wemm * editor -- 48b8ba871bSPeter Wemm * Main editor routine. 49b8ba871bSPeter Wemm * 50b8ba871bSPeter Wemm * PUBLIC: int editor __P((GS *, int, char *[])); 51b8ba871bSPeter Wemm */ 52b8ba871bSPeter Wemm int 53b8ba871bSPeter Wemm editor(gp, argc, argv) 54b8ba871bSPeter Wemm GS *gp; 55b8ba871bSPeter Wemm int argc; 56b8ba871bSPeter Wemm char *argv[]; 57b8ba871bSPeter Wemm { 58b8ba871bSPeter Wemm extern int optind; 59b8ba871bSPeter Wemm extern char *optarg; 60b8ba871bSPeter Wemm const char *p; 61b8ba871bSPeter Wemm EVENT ev; 62b8ba871bSPeter Wemm FREF *frp; 63b8ba871bSPeter Wemm SCR *sp; 64b8ba871bSPeter Wemm size_t len; 65b8ba871bSPeter Wemm u_int flags; 66b8ba871bSPeter Wemm int ch, flagchk, lflag, secure, startup, readonly, rval, silent; 67b8ba871bSPeter Wemm char *tag_f, *wsizearg, path[256]; 68b8ba871bSPeter Wemm 69b8ba871bSPeter Wemm /* Initialize the busy routine, if not defined by the screen. */ 70b8ba871bSPeter Wemm if (gp->scr_busy == NULL) 71b8ba871bSPeter Wemm gp->scr_busy = vs_busy; 72b8ba871bSPeter Wemm /* Initialize the message routine, if not defined by the screen. */ 73b8ba871bSPeter Wemm if (gp->scr_msg == NULL) 74b8ba871bSPeter Wemm gp->scr_msg = vs_msg; 75b8ba871bSPeter Wemm 76b8ba871bSPeter Wemm /* Common global structure initialization. */ 77b8ba871bSPeter Wemm CIRCLEQ_INIT(&gp->dq); 78b8ba871bSPeter Wemm CIRCLEQ_INIT(&gp->hq); 79b8ba871bSPeter Wemm LIST_INIT(&gp->ecq); 80b8ba871bSPeter Wemm LIST_INSERT_HEAD(&gp->ecq, &gp->excmd, q); 81b8ba871bSPeter Wemm gp->noprint = DEFAULT_NOPRINT; 82b8ba871bSPeter Wemm 83b8ba871bSPeter Wemm /* Structures shared by screens so stored in the GS structure. */ 84b8ba871bSPeter Wemm CIRCLEQ_INIT(&gp->frefq); 85b8ba871bSPeter Wemm CIRCLEQ_INIT(&gp->dcb_store.textq); 86b8ba871bSPeter Wemm LIST_INIT(&gp->cutq); 87b8ba871bSPeter Wemm LIST_INIT(&gp->seqq); 88b8ba871bSPeter Wemm 89b8ba871bSPeter Wemm /* Set initial screen type and mode based on the program name. */ 90b8ba871bSPeter Wemm readonly = 0; 91b8ba871bSPeter Wemm if (!strcmp(gp->progname, "ex") || !strcmp(gp->progname, "nex")) 92b8ba871bSPeter Wemm LF_INIT(SC_EX); 93b8ba871bSPeter Wemm else { 94b8ba871bSPeter Wemm /* Nview, view are readonly. */ 95b8ba871bSPeter Wemm if (!strcmp(gp->progname, "nview") || 96b8ba871bSPeter Wemm !strcmp(gp->progname, "view")) 97b8ba871bSPeter Wemm readonly = 1; 98b8ba871bSPeter Wemm 99b8ba871bSPeter Wemm /* Vi is the default. */ 100b8ba871bSPeter Wemm LF_INIT(SC_VI); 101b8ba871bSPeter Wemm } 102b8ba871bSPeter Wemm 103b8ba871bSPeter Wemm /* Convert old-style arguments into new-style ones. */ 104b8ba871bSPeter Wemm if (v_obsolete(gp->progname, argv)) 105b8ba871bSPeter Wemm return (1); 106b8ba871bSPeter Wemm 107b8ba871bSPeter Wemm /* Parse the arguments. */ 108b8ba871bSPeter Wemm flagchk = '\0'; 109b8ba871bSPeter Wemm tag_f = wsizearg = NULL; 110b8ba871bSPeter Wemm lflag = secure = silent = 0; 111b8ba871bSPeter Wemm startup = 1; 112b8ba871bSPeter Wemm 113b8ba871bSPeter Wemm /* Set the file snapshot flag. */ 114b8ba871bSPeter Wemm F_SET(gp, G_SNAPSHOT); 115b8ba871bSPeter Wemm 116b8ba871bSPeter Wemm #ifdef DEBUG 117b8ba871bSPeter Wemm while ((ch = getopt(argc, argv, "c:D:eFlRrSsT:t:vw:")) != EOF) 118b8ba871bSPeter Wemm #else 119b8ba871bSPeter Wemm while ((ch = getopt(argc, argv, "c:eFlRrSst:vw:")) != EOF) 120b8ba871bSPeter Wemm #endif 121b8ba871bSPeter Wemm switch (ch) { 122b8ba871bSPeter Wemm case 'c': /* Run the command. */ 123b8ba871bSPeter Wemm /* 124b8ba871bSPeter Wemm * XXX 125b8ba871bSPeter Wemm * We should support multiple -c options. 126b8ba871bSPeter Wemm */ 127b8ba871bSPeter Wemm if (gp->c_option != NULL) { 128b8ba871bSPeter Wemm v_estr(gp->progname, 0, 129b8ba871bSPeter Wemm "only one -c command may be specified."); 130b8ba871bSPeter Wemm return (1); 131b8ba871bSPeter Wemm } 132b8ba871bSPeter Wemm gp->c_option = optarg; 133b8ba871bSPeter Wemm break; 134b8ba871bSPeter Wemm #ifdef DEBUG 135b8ba871bSPeter Wemm case 'D': 136b8ba871bSPeter Wemm switch (optarg[0]) { 137b8ba871bSPeter Wemm case 's': 138b8ba871bSPeter Wemm startup = 0; 139b8ba871bSPeter Wemm break; 140b8ba871bSPeter Wemm case 'w': 141b8ba871bSPeter Wemm attach(gp); 142b8ba871bSPeter Wemm break; 143b8ba871bSPeter Wemm default: 144b8ba871bSPeter Wemm v_estr(gp->progname, 0, 145b8ba871bSPeter Wemm "usage: -D requires s or w argument."); 146b8ba871bSPeter Wemm return (1); 147b8ba871bSPeter Wemm } 148b8ba871bSPeter Wemm break; 149b8ba871bSPeter Wemm #endif 150b8ba871bSPeter Wemm case 'e': /* Ex mode. */ 151b8ba871bSPeter Wemm LF_CLR(SC_VI); 152b8ba871bSPeter Wemm LF_SET(SC_EX); 153b8ba871bSPeter Wemm break; 154b8ba871bSPeter Wemm case 'F': /* No snapshot. */ 155b8ba871bSPeter Wemm F_CLR(gp, G_SNAPSHOT); 156b8ba871bSPeter Wemm break; 157b8ba871bSPeter Wemm case 'l': /* Set lisp, showmatch options. */ 158b8ba871bSPeter Wemm lflag = 1; 159b8ba871bSPeter Wemm break; 160b8ba871bSPeter Wemm case 'R': /* Readonly. */ 161b8ba871bSPeter Wemm readonly = 1; 162b8ba871bSPeter Wemm break; 163b8ba871bSPeter Wemm case 'r': /* Recover. */ 164b8ba871bSPeter Wemm if (flagchk == 't') { 165b8ba871bSPeter Wemm v_estr(gp->progname, 0, 166b8ba871bSPeter Wemm "only one of -r and -t may be specified."); 167b8ba871bSPeter Wemm return (1); 168b8ba871bSPeter Wemm } 169b8ba871bSPeter Wemm flagchk = 'r'; 170b8ba871bSPeter Wemm break; 171b8ba871bSPeter Wemm case 'S': 172b8ba871bSPeter Wemm secure = 1; 173b8ba871bSPeter Wemm break; 174b8ba871bSPeter Wemm case 's': 175b8ba871bSPeter Wemm silent = 1; 176b8ba871bSPeter Wemm break; 177b8ba871bSPeter Wemm #ifdef DEBUG 178b8ba871bSPeter Wemm case 'T': /* Trace. */ 179b8ba871bSPeter Wemm if ((gp->tracefp = fopen(optarg, "w")) == NULL) { 180b8ba871bSPeter Wemm v_estr(gp->progname, errno, optarg); 181b8ba871bSPeter Wemm goto err; 182b8ba871bSPeter Wemm } 183b8ba871bSPeter Wemm (void)fprintf(gp->tracefp, 184b8ba871bSPeter Wemm "\n===\ntrace: open %s\n", optarg); 185b8ba871bSPeter Wemm break; 186b8ba871bSPeter Wemm #endif 187b8ba871bSPeter Wemm case 't': /* Tag. */ 188b8ba871bSPeter Wemm if (flagchk == 'r') { 189b8ba871bSPeter Wemm v_estr(gp->progname, 0, 190b8ba871bSPeter Wemm "only one of -r and -t may be specified."); 191b8ba871bSPeter Wemm return (1); 192b8ba871bSPeter Wemm } 193b8ba871bSPeter Wemm if (flagchk == 't') { 194b8ba871bSPeter Wemm v_estr(gp->progname, 0, 195b8ba871bSPeter Wemm "only one tag file may be specified."); 196b8ba871bSPeter Wemm return (1); 197b8ba871bSPeter Wemm } 198b8ba871bSPeter Wemm flagchk = 't'; 199b8ba871bSPeter Wemm tag_f = optarg; 200b8ba871bSPeter Wemm break; 201b8ba871bSPeter Wemm case 'v': /* Vi mode. */ 202b8ba871bSPeter Wemm LF_CLR(SC_EX); 203b8ba871bSPeter Wemm LF_SET(SC_VI); 204b8ba871bSPeter Wemm break; 205b8ba871bSPeter Wemm case 'w': 206b8ba871bSPeter Wemm wsizearg = optarg; 207b8ba871bSPeter Wemm break; 208b8ba871bSPeter Wemm case '?': 209b8ba871bSPeter Wemm default: 210b8ba871bSPeter Wemm (void)gp->scr_usage(); 211b8ba871bSPeter Wemm return (1); 212b8ba871bSPeter Wemm } 213b8ba871bSPeter Wemm argc -= optind; 214b8ba871bSPeter Wemm argv += optind; 215b8ba871bSPeter Wemm 216b8ba871bSPeter Wemm /* 217b8ba871bSPeter Wemm * -s option is only meaningful to ex. 218b8ba871bSPeter Wemm * 219b8ba871bSPeter Wemm * If not reading from a terminal, it's like -s was specified. 220b8ba871bSPeter Wemm */ 221b8ba871bSPeter Wemm if (silent && !LF_ISSET(SC_EX)) { 222b8ba871bSPeter Wemm v_estr(gp->progname, 0, "-s option is only applicable to ex."); 223b8ba871bSPeter Wemm goto err; 224b8ba871bSPeter Wemm } 225b8ba871bSPeter Wemm if (LF_ISSET(SC_EX) && F_ISSET(gp, G_SCRIPTED)) 226b8ba871bSPeter Wemm silent = 1; 227b8ba871bSPeter Wemm 228b8ba871bSPeter Wemm /* 229b8ba871bSPeter Wemm * Build and initialize the first/current screen. This is a bit 230b8ba871bSPeter Wemm * tricky. If an error is returned, we may or may not have a 231b8ba871bSPeter Wemm * screen structure. If we have a screen structure, put it on a 232b8ba871bSPeter Wemm * display queue so that the error messages get displayed. 233b8ba871bSPeter Wemm * 234b8ba871bSPeter Wemm * !!! 235b8ba871bSPeter Wemm * Everything we do until we go interactive is done in ex mode. 236b8ba871bSPeter Wemm */ 237b8ba871bSPeter Wemm if (screen_init(gp, NULL, &sp)) { 238b8ba871bSPeter Wemm if (sp != NULL) 239b8ba871bSPeter Wemm CIRCLEQ_INSERT_HEAD(&gp->dq, sp, q); 240b8ba871bSPeter Wemm goto err; 241b8ba871bSPeter Wemm } 242b8ba871bSPeter Wemm F_SET(sp, SC_EX); 243b8ba871bSPeter Wemm CIRCLEQ_INSERT_HEAD(&gp->dq, sp, q); 244b8ba871bSPeter Wemm 245b8ba871bSPeter Wemm if (v_key_init(sp)) /* Special key initialization. */ 246b8ba871bSPeter Wemm goto err; 247b8ba871bSPeter Wemm 248b8ba871bSPeter Wemm { int oargs[5], *oargp = oargs; 249b8ba871bSPeter Wemm if (lflag) { /* Command-line options. */ 250b8ba871bSPeter Wemm *oargp++ = O_LISP; 251b8ba871bSPeter Wemm *oargp++ = O_SHOWMATCH; 252b8ba871bSPeter Wemm } 253b8ba871bSPeter Wemm if (readonly) 254b8ba871bSPeter Wemm *oargp++ = O_READONLY; 255b8ba871bSPeter Wemm if (secure) 256b8ba871bSPeter Wemm *oargp++ = O_SECURE; 257b8ba871bSPeter Wemm *oargp = -1; /* Options initialization. */ 258b8ba871bSPeter Wemm if (opts_init(sp, oargs)) 259b8ba871bSPeter Wemm goto err; 260b8ba871bSPeter Wemm } 261b8ba871bSPeter Wemm if (wsizearg != NULL) { 262b8ba871bSPeter Wemm ARGS *av[2], a, b; 263b8ba871bSPeter Wemm (void)snprintf(path, sizeof(path), "window=%s", wsizearg); 264b8ba871bSPeter Wemm a.bp = (CHAR_T *)path; 265b8ba871bSPeter Wemm a.len = strlen(path); 266b8ba871bSPeter Wemm b.bp = NULL; 267b8ba871bSPeter Wemm b.len = 0; 268b8ba871bSPeter Wemm av[0] = &a; 269b8ba871bSPeter Wemm av[1] = &b; 270b8ba871bSPeter Wemm (void)opts_set(sp, av, NULL); 271b8ba871bSPeter Wemm } 272b8ba871bSPeter Wemm if (silent) { /* Ex batch mode option values. */ 273b8ba871bSPeter Wemm O_CLR(sp, O_AUTOPRINT); 274b8ba871bSPeter Wemm O_CLR(sp, O_PROMPT); 275b8ba871bSPeter Wemm O_CLR(sp, O_VERBOSE); 276b8ba871bSPeter Wemm O_CLR(sp, O_WARN); 277b8ba871bSPeter Wemm F_SET(sp, SC_EX_SILENT); 278b8ba871bSPeter Wemm } 279b8ba871bSPeter Wemm 280b8ba871bSPeter Wemm sp->rows = O_VAL(sp, O_LINES); /* Make ex formatting work. */ 281b8ba871bSPeter Wemm sp->cols = O_VAL(sp, O_COLUMNS); 282b8ba871bSPeter Wemm 283b8ba871bSPeter Wemm if (!silent && startup) { /* Read EXINIT, exrc files. */ 284b8ba871bSPeter Wemm if (ex_exrc(sp)) 285b8ba871bSPeter Wemm goto err; 286b8ba871bSPeter Wemm if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { 287b8ba871bSPeter Wemm if (screen_end(sp)) 288b8ba871bSPeter Wemm goto err; 289b8ba871bSPeter Wemm goto done; 290b8ba871bSPeter Wemm } 291b8ba871bSPeter Wemm } 292b8ba871bSPeter Wemm 293b8ba871bSPeter Wemm /* 294b8ba871bSPeter Wemm * List recovery files if -r specified without file arguments. 295b8ba871bSPeter Wemm * Note, options must be initialized and startup information 296b8ba871bSPeter Wemm * read before doing this. 297b8ba871bSPeter Wemm */ 298b8ba871bSPeter Wemm if (flagchk == 'r' && argv[0] == NULL) { 299b8ba871bSPeter Wemm if (rcv_list(sp)) 300b8ba871bSPeter Wemm goto err; 301b8ba871bSPeter Wemm if (screen_end(sp)) 302b8ba871bSPeter Wemm goto err; 303b8ba871bSPeter Wemm goto done; 304b8ba871bSPeter Wemm } 305b8ba871bSPeter Wemm 306b8ba871bSPeter Wemm /* 307b8ba871bSPeter Wemm * !!! 308b8ba871bSPeter Wemm * Initialize the default ^D, ^U scrolling value here, after the 309b8ba871bSPeter Wemm * user has had every opportunity to set the window option. 310b8ba871bSPeter Wemm * 311b8ba871bSPeter Wemm * It's historic practice that changing the value of the window 312b8ba871bSPeter Wemm * option did not alter the default scrolling value, only giving 313b8ba871bSPeter Wemm * a count to ^D/^U did that. 314b8ba871bSPeter Wemm */ 315b8ba871bSPeter Wemm sp->defscroll = (O_VAL(sp, O_WINDOW) + 1) / 2; 316b8ba871bSPeter Wemm 317b8ba871bSPeter Wemm /* 318b8ba871bSPeter Wemm * If we don't have a command-line option, switch into the right 319b8ba871bSPeter Wemm * editor now, so that we position default files correctly, and 320b8ba871bSPeter Wemm * so that any tags file file-already-locked messages are in the 321b8ba871bSPeter Wemm * vi screen, not the ex screen. 322b8ba871bSPeter Wemm * 323b8ba871bSPeter Wemm * XXX 324b8ba871bSPeter Wemm * If we have a command-line option, the error message can end 325b8ba871bSPeter Wemm * up in the wrong place, but I think that the combination is 326b8ba871bSPeter Wemm * unlikely. 327b8ba871bSPeter Wemm */ 328b8ba871bSPeter Wemm if (gp->c_option == NULL) { 329b8ba871bSPeter Wemm F_CLR(sp, SC_EX | SC_VI); 330b8ba871bSPeter Wemm F_SET(sp, LF_ISSET(SC_EX | SC_VI)); 331b8ba871bSPeter Wemm } 332b8ba871bSPeter Wemm 333b8ba871bSPeter Wemm /* Open a tag file if specified. */ 334b8ba871bSPeter Wemm if (tag_f != NULL && ex_tag_first(sp, tag_f)) 335b8ba871bSPeter Wemm goto err; 336b8ba871bSPeter Wemm 337b8ba871bSPeter Wemm /* 338b8ba871bSPeter Wemm * Append any remaining arguments as file names. Files are recovery 339b8ba871bSPeter Wemm * files if -r specified. If the tag option or ex startup commands 340b8ba871bSPeter Wemm * loaded a file, then any file arguments are going to come after it. 341b8ba871bSPeter Wemm */ 342b8ba871bSPeter Wemm if (*argv != NULL) { 343b8ba871bSPeter Wemm if (sp->frp != NULL) { 344b8ba871bSPeter Wemm /* Cheat -- we know we have an extra argv slot. */ 345b8ba871bSPeter Wemm MALLOC_NOMSG(sp, 346b8ba871bSPeter Wemm *--argv, char *, strlen(sp->frp->name) + 1); 347b8ba871bSPeter Wemm if (*argv == NULL) { 348b8ba871bSPeter Wemm v_estr(gp->progname, errno, NULL); 349b8ba871bSPeter Wemm goto err; 350b8ba871bSPeter Wemm } 351b8ba871bSPeter Wemm (void)strcpy(*argv, sp->frp->name); 352b8ba871bSPeter Wemm } 353b8ba871bSPeter Wemm sp->argv = sp->cargv = argv; 354b8ba871bSPeter Wemm F_SET(sp, SC_ARGNOFREE); 355b8ba871bSPeter Wemm if (flagchk == 'r') 356b8ba871bSPeter Wemm F_SET(sp, SC_ARGRECOVER); 357b8ba871bSPeter Wemm } 358b8ba871bSPeter Wemm 359b8ba871bSPeter Wemm /* 360b8ba871bSPeter Wemm * If the ex startup commands and or/the tag option haven't already 361b8ba871bSPeter Wemm * created a file, create one. If no command-line files were given, 362b8ba871bSPeter Wemm * use a temporary file. 363b8ba871bSPeter Wemm */ 364b8ba871bSPeter Wemm if (sp->frp == NULL) { 365b8ba871bSPeter Wemm if (sp->argv == NULL) { 366b8ba871bSPeter Wemm if ((frp = file_add(sp, NULL)) == NULL) 367b8ba871bSPeter Wemm goto err; 368b8ba871bSPeter Wemm } else { 369b8ba871bSPeter Wemm if ((frp = file_add(sp, (CHAR_T *)sp->argv[0])) == NULL) 370b8ba871bSPeter Wemm goto err; 371b8ba871bSPeter Wemm if (F_ISSET(sp, SC_ARGRECOVER)) 372b8ba871bSPeter Wemm F_SET(frp, FR_RECOVER); 373b8ba871bSPeter Wemm } 374b8ba871bSPeter Wemm 375b8ba871bSPeter Wemm if (file_init(sp, frp, NULL, 0)) 376b8ba871bSPeter Wemm goto err; 377b8ba871bSPeter Wemm if (EXCMD_RUNNING(gp)) { 378b8ba871bSPeter Wemm (void)ex_cmd(sp); 379b8ba871bSPeter Wemm if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { 380b8ba871bSPeter Wemm if (screen_end(sp)) 381b8ba871bSPeter Wemm goto err; 382b8ba871bSPeter Wemm goto done; 383b8ba871bSPeter Wemm } 384b8ba871bSPeter Wemm } 385b8ba871bSPeter Wemm } 386b8ba871bSPeter Wemm 387b8ba871bSPeter Wemm /* 388b8ba871bSPeter Wemm * Check to see if we need to wait for ex. If SC_SCR_EX is set, ex 389b8ba871bSPeter Wemm * was forced to initialize the screen during startup. We'd like to 390b8ba871bSPeter Wemm * wait for a single character from the user, but we can't because 391b8ba871bSPeter Wemm * we're not in raw mode. We can't switch to raw mode because the 392b8ba871bSPeter Wemm * vi initialization will switch to xterm's alternate screen, causing 393b8ba871bSPeter Wemm * us to lose the messages we're pausing to make sure the user read. 394b8ba871bSPeter Wemm * So, wait for a complete line. 395b8ba871bSPeter Wemm */ 396b8ba871bSPeter Wemm if (F_ISSET(sp, SC_SCR_EX)) { 397b8ba871bSPeter Wemm p = msg_cmsg(sp, CMSG_CONT_R, &len); 398b8ba871bSPeter Wemm (void)write(STDOUT_FILENO, p, len); 399b8ba871bSPeter Wemm for (;;) { 400b8ba871bSPeter Wemm if (v_event_get(sp, &ev, 0, 0)) 401b8ba871bSPeter Wemm goto err; 402b8ba871bSPeter Wemm if (ev.e_event == E_INTERRUPT || 403b8ba871bSPeter Wemm ev.e_event == E_CHARACTER && 404b8ba871bSPeter Wemm (ev.e_value == K_CR || ev.e_value == K_NL)) 405b8ba871bSPeter Wemm break; 406b8ba871bSPeter Wemm (void)gp->scr_bell(sp); 407b8ba871bSPeter Wemm } 408b8ba871bSPeter Wemm } 409b8ba871bSPeter Wemm 410b8ba871bSPeter Wemm /* Switch into the right editor, regardless. */ 411b8ba871bSPeter Wemm F_CLR(sp, SC_EX | SC_VI); 412b8ba871bSPeter Wemm F_SET(sp, LF_ISSET(SC_EX | SC_VI) | SC_STATUS_CNT); 413b8ba871bSPeter Wemm 414b8ba871bSPeter Wemm /* 415b8ba871bSPeter Wemm * Main edit loop. Vi handles split screens itself, we only return 416b8ba871bSPeter Wemm * here when switching editor modes or restarting the screen. 417b8ba871bSPeter Wemm */ 418b8ba871bSPeter Wemm while (sp != NULL) 419b8ba871bSPeter Wemm if (F_ISSET(sp, SC_EX) ? ex(&sp) : vi(&sp)) 420b8ba871bSPeter Wemm goto err; 421b8ba871bSPeter Wemm 422b8ba871bSPeter Wemm done: rval = 0; 423b8ba871bSPeter Wemm if (0) 424b8ba871bSPeter Wemm err: rval = 1; 425b8ba871bSPeter Wemm 426b8ba871bSPeter Wemm /* Clean out the global structure. */ 427b8ba871bSPeter Wemm v_end(gp); 428b8ba871bSPeter Wemm 429b8ba871bSPeter Wemm return (rval); 430b8ba871bSPeter Wemm } 431b8ba871bSPeter Wemm 432b8ba871bSPeter Wemm /* 433b8ba871bSPeter Wemm * v_end -- 434b8ba871bSPeter Wemm * End the program, discarding screens and most of the global area. 435b8ba871bSPeter Wemm * 436b8ba871bSPeter Wemm * PUBLIC: void v_end __P((GS *)); 437b8ba871bSPeter Wemm */ 438b8ba871bSPeter Wemm void 439b8ba871bSPeter Wemm v_end(gp) 440b8ba871bSPeter Wemm GS *gp; 441b8ba871bSPeter Wemm { 442b8ba871bSPeter Wemm MSGS *mp; 443b8ba871bSPeter Wemm SCR *sp; 444b8ba871bSPeter Wemm 445b8ba871bSPeter Wemm /* If there are any remaining screens, kill them off. */ 446b8ba871bSPeter Wemm if (gp->ccl_sp != NULL) { 447b8ba871bSPeter Wemm (void)file_end(gp->ccl_sp, NULL, 1); 448b8ba871bSPeter Wemm (void)screen_end(gp->ccl_sp); 449b8ba871bSPeter Wemm } 450b8ba871bSPeter Wemm while ((sp = gp->dq.cqh_first) != (void *)&gp->dq) 451b8ba871bSPeter Wemm (void)screen_end(sp); 452b8ba871bSPeter Wemm while ((sp = gp->hq.cqh_first) != (void *)&gp->hq) 453b8ba871bSPeter Wemm (void)screen_end(sp); 454b8ba871bSPeter Wemm 455b8ba871bSPeter Wemm #ifdef HAVE_PERL_INTERP 456b8ba871bSPeter Wemm perl_end(gp); 457b8ba871bSPeter Wemm #endif 458b8ba871bSPeter Wemm 459b8ba871bSPeter Wemm #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY) 460b8ba871bSPeter Wemm { FREF *frp; 461b8ba871bSPeter Wemm /* Free FREF's. */ 462b8ba871bSPeter Wemm while ((frp = gp->frefq.cqh_first) != (FREF *)&gp->frefq) { 463b8ba871bSPeter Wemm CIRCLEQ_REMOVE(&gp->frefq, frp, q); 464b8ba871bSPeter Wemm if (frp->name != NULL) 465b8ba871bSPeter Wemm free(frp->name); 466b8ba871bSPeter Wemm if (frp->tname != NULL) 467b8ba871bSPeter Wemm free(frp->tname); 468b8ba871bSPeter Wemm free(frp); 469b8ba871bSPeter Wemm } 470b8ba871bSPeter Wemm } 471b8ba871bSPeter Wemm 472b8ba871bSPeter Wemm /* Free key input queue. */ 473b8ba871bSPeter Wemm if (gp->i_event != NULL) 474b8ba871bSPeter Wemm free(gp->i_event); 475b8ba871bSPeter Wemm 476b8ba871bSPeter Wemm /* Free cut buffers. */ 477b8ba871bSPeter Wemm cut_close(gp); 478b8ba871bSPeter Wemm 479b8ba871bSPeter Wemm /* Free map sequences. */ 480b8ba871bSPeter Wemm seq_close(gp); 481b8ba871bSPeter Wemm 482b8ba871bSPeter Wemm /* Free default buffer storage. */ 483b8ba871bSPeter Wemm (void)text_lfree(&gp->dcb_store.textq); 484b8ba871bSPeter Wemm 485b8ba871bSPeter Wemm /* Close message catalogs. */ 486b8ba871bSPeter Wemm msg_close(gp); 487b8ba871bSPeter Wemm #endif 488b8ba871bSPeter Wemm 489b8ba871bSPeter Wemm /* Ring the bell if scheduled. */ 490b8ba871bSPeter Wemm if (F_ISSET(gp, G_BELLSCHED)) 491b8ba871bSPeter Wemm (void)fprintf(stderr, "\07"); /* \a */ 492b8ba871bSPeter Wemm 493b8ba871bSPeter Wemm /* 494b8ba871bSPeter Wemm * Flush any remaining messages. If a message is here, it's almost 495b8ba871bSPeter Wemm * certainly the message about the event that killed us (although 496b8ba871bSPeter Wemm * it's possible that the user is sourcing a file that exits from the 497b8ba871bSPeter Wemm * editor). 498b8ba871bSPeter Wemm */ 499b8ba871bSPeter Wemm while ((mp = gp->msgq.lh_first) != NULL) { 500b8ba871bSPeter Wemm (void)fprintf(stderr, "%s%.*s", 501b8ba871bSPeter Wemm mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf); 502b8ba871bSPeter Wemm LIST_REMOVE(mp, q); 503b8ba871bSPeter Wemm #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY) 504b8ba871bSPeter Wemm free(mp->buf); 505b8ba871bSPeter Wemm free(mp); 506b8ba871bSPeter Wemm #endif 507b8ba871bSPeter Wemm } 508b8ba871bSPeter Wemm 509b8ba871bSPeter Wemm #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY) 510b8ba871bSPeter Wemm /* Free any temporary space. */ 511b8ba871bSPeter Wemm if (gp->tmp_bp != NULL) 512b8ba871bSPeter Wemm free(gp->tmp_bp); 513b8ba871bSPeter Wemm 514b8ba871bSPeter Wemm #if defined(DEBUG) 515b8ba871bSPeter Wemm /* Close debugging file descriptor. */ 516b8ba871bSPeter Wemm if (gp->tracefp != NULL) 517b8ba871bSPeter Wemm (void)fclose(gp->tracefp); 518b8ba871bSPeter Wemm #endif 519b8ba871bSPeter Wemm #endif 520b8ba871bSPeter Wemm } 521b8ba871bSPeter Wemm 522b8ba871bSPeter Wemm /* 523b8ba871bSPeter Wemm * v_obsolete -- 524b8ba871bSPeter Wemm * Convert historic arguments into something getopt(3) will like. 525b8ba871bSPeter Wemm */ 526b8ba871bSPeter Wemm static int 527b8ba871bSPeter Wemm v_obsolete(name, argv) 528b8ba871bSPeter Wemm char *name, *argv[]; 529b8ba871bSPeter Wemm { 530b8ba871bSPeter Wemm size_t len; 531b8ba871bSPeter Wemm char *p; 532b8ba871bSPeter Wemm 533b8ba871bSPeter Wemm /* 534b8ba871bSPeter Wemm * Translate old style arguments into something getopt will like. 535b8ba871bSPeter Wemm * Make sure it's not text space memory, because ex modifies the 536b8ba871bSPeter Wemm * strings. 537b8ba871bSPeter Wemm * Change "+" into "-c$". 538b8ba871bSPeter Wemm * Change "+<anything else>" into "-c<anything else>". 539b8ba871bSPeter Wemm * Change "-" into "-s" 540b8ba871bSPeter Wemm * The c, T, t and w options take arguments so they can't be 541b8ba871bSPeter Wemm * special arguments. 542b8ba871bSPeter Wemm * 543b8ba871bSPeter Wemm * Stop if we find "--" as an argument, the user may want to edit 544b8ba871bSPeter Wemm * a file named "+foo". 545b8ba871bSPeter Wemm */ 546b8ba871bSPeter Wemm while (*++argv && strcmp(argv[0], "--")) 547b8ba871bSPeter Wemm if (argv[0][0] == '+') { 548b8ba871bSPeter Wemm if (argv[0][1] == '\0') { 549b8ba871bSPeter Wemm MALLOC_NOMSG(NULL, argv[0], char *, 4); 550b8ba871bSPeter Wemm if (argv[0] == NULL) 551b8ba871bSPeter Wemm goto nomem; 552b8ba871bSPeter Wemm (void)strcpy(argv[0], "-c$"); 553b8ba871bSPeter Wemm } else { 554b8ba871bSPeter Wemm p = argv[0]; 555b8ba871bSPeter Wemm len = strlen(argv[0]); 556b8ba871bSPeter Wemm MALLOC_NOMSG(NULL, argv[0], char *, len + 2); 557b8ba871bSPeter Wemm if (argv[0] == NULL) 558b8ba871bSPeter Wemm goto nomem; 559b8ba871bSPeter Wemm argv[0][0] = '-'; 560b8ba871bSPeter Wemm argv[0][1] = 'c'; 561b8ba871bSPeter Wemm (void)strcpy(argv[0] + 2, p + 1); 562b8ba871bSPeter Wemm } 563b8ba871bSPeter Wemm } else if (argv[0][0] == '-') 564b8ba871bSPeter Wemm if (argv[0][1] == '\0') { 565b8ba871bSPeter Wemm MALLOC_NOMSG(NULL, argv[0], char *, 3); 566b8ba871bSPeter Wemm if (argv[0] == NULL) { 567b8ba871bSPeter Wemm nomem: v_estr(name, errno, NULL); 568b8ba871bSPeter Wemm return (1); 569b8ba871bSPeter Wemm } 570b8ba871bSPeter Wemm (void)strcpy(argv[0], "-s"); 571b8ba871bSPeter Wemm } else 572b8ba871bSPeter Wemm if ((argv[0][1] == 'c' || argv[0][1] == 'T' || 573b8ba871bSPeter Wemm argv[0][1] == 't' || argv[0][1] == 'w') && 574b8ba871bSPeter Wemm argv[0][2] == '\0') 575b8ba871bSPeter Wemm ++argv; 576b8ba871bSPeter Wemm return (0); 577b8ba871bSPeter Wemm } 578b8ba871bSPeter Wemm 579b8ba871bSPeter Wemm #ifdef DEBUG 580b8ba871bSPeter Wemm static void 581b8ba871bSPeter Wemm attach(gp) 582b8ba871bSPeter Wemm GS *gp; 583b8ba871bSPeter Wemm { 584b8ba871bSPeter Wemm int fd; 585b8ba871bSPeter Wemm char ch; 586b8ba871bSPeter Wemm 587b8ba871bSPeter Wemm if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) { 588b8ba871bSPeter Wemm v_estr(gp->progname, errno, _PATH_TTY); 589b8ba871bSPeter Wemm return; 590b8ba871bSPeter Wemm } 591b8ba871bSPeter Wemm 592b8ba871bSPeter Wemm (void)printf("process %lu waiting, enter <CR> to continue: ", 593b8ba871bSPeter Wemm (u_long)getpid()); 594b8ba871bSPeter Wemm (void)fflush(stdout); 595b8ba871bSPeter Wemm 596b8ba871bSPeter Wemm do { 597b8ba871bSPeter Wemm if (read(fd, &ch, 1) != 1) { 598b8ba871bSPeter Wemm (void)close(fd); 599b8ba871bSPeter Wemm return; 600b8ba871bSPeter Wemm } 601b8ba871bSPeter Wemm } while (ch != '\n' && ch != '\r'); 602b8ba871bSPeter Wemm (void)close(fd); 603b8ba871bSPeter Wemm } 604b8ba871bSPeter Wemm #endif 605b8ba871bSPeter Wemm 606b8ba871bSPeter Wemm static void 607b8ba871bSPeter Wemm v_estr(name, eno, msg) 608b8ba871bSPeter Wemm char *name, *msg; 609b8ba871bSPeter Wemm int eno; 610b8ba871bSPeter Wemm { 611b8ba871bSPeter Wemm (void)fprintf(stderr, "%s", name); 612b8ba871bSPeter Wemm if (msg != NULL) 613b8ba871bSPeter Wemm (void)fprintf(stderr, ": %s", msg); 614b8ba871bSPeter Wemm if (eno) 615b8ba871bSPeter Wemm (void)fprintf(stderr, ": %s", strerror(errno)); 616b8ba871bSPeter Wemm (void)fprintf(stderr, "\n"); 617b8ba871bSPeter Wemm } 618