10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*4488Scf46844 * Common Development and Distribution License (the "License").
6*4488Scf46844 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*4488Scf46844 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include "ex.h"
340Sstevel@tonic-gate #include "ex_argv.h"
350Sstevel@tonic-gate #include "ex_temp.h"
360Sstevel@tonic-gate #include "ex_tty.h"
370Sstevel@tonic-gate #include <stdlib.h>
380Sstevel@tonic-gate #include <locale.h>
390Sstevel@tonic-gate #include <stdio.h>
400Sstevel@tonic-gate #ifdef TRACE
410Sstevel@tonic-gate unsigned char tttrace[BUFSIZ];
420Sstevel@tonic-gate #endif
430Sstevel@tonic-gate
440Sstevel@tonic-gate #define EQ(a, b) (strcmp(a, b) == 0)
450Sstevel@tonic-gate
460Sstevel@tonic-gate char *strrchr();
470Sstevel@tonic-gate void init_re(void);
480Sstevel@tonic-gate
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate * The code for ex is divided as follows:
510Sstevel@tonic-gate *
520Sstevel@tonic-gate * ex.c Entry point and routines handling interrupt, hangup
530Sstevel@tonic-gate * signals; initialization code.
540Sstevel@tonic-gate *
550Sstevel@tonic-gate * ex_addr.c Address parsing routines for command mode decoding.
560Sstevel@tonic-gate * Routines to set and check address ranges on commands.
570Sstevel@tonic-gate *
580Sstevel@tonic-gate * ex_cmds.c Command mode command decoding.
590Sstevel@tonic-gate *
600Sstevel@tonic-gate * ex_cmds2.c Subroutines for command decoding and processing of
610Sstevel@tonic-gate * file names in the argument list. Routines to print
620Sstevel@tonic-gate * messages and reset state when errors occur.
630Sstevel@tonic-gate *
640Sstevel@tonic-gate * ex_cmdsub.c Subroutines which implement command mode functions
650Sstevel@tonic-gate * such as append, delete, join.
660Sstevel@tonic-gate *
670Sstevel@tonic-gate * ex_data.c Initialization of options.
680Sstevel@tonic-gate *
690Sstevel@tonic-gate * ex_get.c Command mode input routines.
700Sstevel@tonic-gate *
710Sstevel@tonic-gate * ex_io.c General input/output processing: file i/o, unix
720Sstevel@tonic-gate * escapes, filtering, source commands, preserving
730Sstevel@tonic-gate * and recovering.
740Sstevel@tonic-gate *
750Sstevel@tonic-gate * ex_put.c Terminal driving and optimizing routines for low-level
760Sstevel@tonic-gate * output (cursor-positioning); output line formatting
770Sstevel@tonic-gate * routines.
780Sstevel@tonic-gate *
790Sstevel@tonic-gate * ex_re.c Global commands, substitute, regular expression
800Sstevel@tonic-gate * compilation and execution.
810Sstevel@tonic-gate *
820Sstevel@tonic-gate * ex_set.c The set command.
830Sstevel@tonic-gate *
840Sstevel@tonic-gate * ex_subr.c Loads of miscellaneous subroutines.
850Sstevel@tonic-gate *
860Sstevel@tonic-gate * ex_temp.c Editor buffer routines for main buffer and also
870Sstevel@tonic-gate * for named buffers (Q registers if you will.)
880Sstevel@tonic-gate *
890Sstevel@tonic-gate * ex_tty.c Terminal dependent initializations from termcap
900Sstevel@tonic-gate * data base, grabbing of tty modes (at beginning
910Sstevel@tonic-gate * and after escapes).
920Sstevel@tonic-gate *
930Sstevel@tonic-gate * ex_unix.c Routines for the ! command and its variations.
940Sstevel@tonic-gate *
950Sstevel@tonic-gate * ex_v*.c Visual/open mode routines... see ex_v.c for a
960Sstevel@tonic-gate * guide to the overall organization.
970Sstevel@tonic-gate */
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * This sets the Version of ex/vi for both the exstrings file and
1010Sstevel@tonic-gate * the version command (":ver").
1020Sstevel@tonic-gate */
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate /* variable used by ":ver" command */
1050Sstevel@tonic-gate unsigned char *Version = (unsigned char *)"Version SVR4.0, Solaris 2.5.0";
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate * NOTE: when changing the Version number, it must be changed in the
1090Sstevel@tonic-gate * following files:
1100Sstevel@tonic-gate *
1110Sstevel@tonic-gate * port/READ_ME
1120Sstevel@tonic-gate * port/ex.c
1130Sstevel@tonic-gate * port/ex.news
1140Sstevel@tonic-gate *
1150Sstevel@tonic-gate */
1160Sstevel@tonic-gate #ifdef XPG4
1170Sstevel@tonic-gate unsigned char *savepat = (unsigned char *) NULL; /* firstpat storage */
1180Sstevel@tonic-gate #endif /* XPG4 */
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate * Main procedure. Process arguments and then
1220Sstevel@tonic-gate * transfer control to the main command processing loop
1230Sstevel@tonic-gate * in the routine commands. We are entered as either "ex", "edit", "vi"
1240Sstevel@tonic-gate * or "view" and the distinction is made here. For edit we just diddle options;
1250Sstevel@tonic-gate * for vi we actually force an early visual command.
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate static unsigned char cryptkey[19]; /* contents of encryption key */
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate static void usage(unsigned char *);
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate static int validate_exrc(unsigned char *);
1320Sstevel@tonic-gate
133802Scf46844 void init(void);
134802Scf46844
1350Sstevel@tonic-gate int
main(int ac,char * av[])136802Scf46844 main(int ac, char *av[])
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate extern char *optarg;
1390Sstevel@tonic-gate extern int optind;
1400Sstevel@tonic-gate unsigned char *rcvname = 0;
1410Sstevel@tonic-gate unsigned char *cp;
1420Sstevel@tonic-gate int c;
1430Sstevel@tonic-gate unsigned char *cmdnam;
1440Sstevel@tonic-gate bool recov = 0;
1450Sstevel@tonic-gate bool ivis = 0;
1460Sstevel@tonic-gate bool itag = 0;
1470Sstevel@tonic-gate bool fast = 0;
1480Sstevel@tonic-gate extern int verbose;
1490Sstevel@tonic-gate int argcounter = 0;
1500Sstevel@tonic-gate extern int tags_flag; /* Set if tag file is not sorted (-S flag) */
1510Sstevel@tonic-gate unsigned char scratch [PATH_MAX+1]; /* temp for sourcing rc file(s) */
1520Sstevel@tonic-gate int vret = 0;
1530Sstevel@tonic-gate unsigned char exrcpath [PATH_MAX+1]; /* temp for sourcing rc file(s) */
1540Sstevel@tonic-gate int toptseen = 0;
1550Sstevel@tonic-gate #ifdef TRACE
1560Sstevel@tonic-gate unsigned char *tracef;
1570Sstevel@tonic-gate #endif
158*4488Scf46844 tagflg = 0;
1590Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1600Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1610Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
1620Sstevel@tonic-gate #endif
1630Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * Immediately grab the tty modes so that we won't
1670Sstevel@tonic-gate * get messed up if an interrupt comes in quickly.
1680Sstevel@tonic-gate */
169802Scf46844 (void) gTTY(2);
1700Sstevel@tonic-gate normf = tty;
1710Sstevel@tonic-gate ppid = getpid();
1720Sstevel@tonic-gate /* Note - this will core dump if you didn't -DSINGLE in CFLAGS */
1730Sstevel@tonic-gate lines = 24;
1740Sstevel@tonic-gate columns = 80; /* until defined right by setupterm */
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * Defend against d's, v's, w's, and a's in directories of
1770Sstevel@tonic-gate * path leading to our true name.
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate if ((cmdnam = (unsigned char *)strrchr(av[0], '/')) != 0)
1800Sstevel@tonic-gate cmdnam++;
1810Sstevel@tonic-gate else
182802Scf46844 cmdnam = (unsigned char *)av[0];
1830Sstevel@tonic-gate
184802Scf46844 if (EQ((char *)cmdnam, "vi"))
1850Sstevel@tonic-gate ivis = 1;
1860Sstevel@tonic-gate else if (EQ(cmdnam, "view")) {
1870Sstevel@tonic-gate ivis = 1;
1880Sstevel@tonic-gate value(vi_READONLY) = 1;
1890Sstevel@tonic-gate } else if (EQ(cmdnam, "vedit")) {
1900Sstevel@tonic-gate ivis = 1;
1910Sstevel@tonic-gate value(vi_NOVICE) = 1;
1920Sstevel@tonic-gate value(vi_REPORT) = 1;
1930Sstevel@tonic-gate value(vi_MAGIC) = 0;
1940Sstevel@tonic-gate value(vi_SHOWMODE) = 1;
1950Sstevel@tonic-gate } else if (EQ(cmdnam, "edit")) {
1960Sstevel@tonic-gate value(vi_NOVICE) = 1;
1970Sstevel@tonic-gate value(vi_REPORT) = 1;
1980Sstevel@tonic-gate value(vi_MAGIC) = 0;
1990Sstevel@tonic-gate value(vi_SHOWMODE) = 1;
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate #ifdef XPG4
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate struct winsize jwin;
2050Sstevel@tonic-gate char *envptr;
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate envlines = envcolumns = -1;
2080Sstevel@tonic-gate oldlines = oldcolumns = -1;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate if (ioctl(0, TIOCGWINSZ, &jwin) != -1) {
2110Sstevel@tonic-gate oldlines = jwin.ws_row;
2120Sstevel@tonic-gate oldcolumns = jwin.ws_col;
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate if ((envptr = getenv("LINES")) != NULL &&
2160Sstevel@tonic-gate *envptr != '\0' && isdigit(*envptr)) {
2170Sstevel@tonic-gate if ((envlines = atoi(envptr)) <= 0) {
2180Sstevel@tonic-gate envlines = -1;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate if ((envptr = getenv("COLUMNS")) != NULL &&
2230Sstevel@tonic-gate *envptr != '\0' && isdigit(*envptr)) {
2240Sstevel@tonic-gate if ((envcolumns = atoi(envptr)) <= 0) {
2250Sstevel@tonic-gate envcolumns = -1;
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate #endif /* XPG4 */
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate draino();
2320Sstevel@tonic-gate pstop();
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * Initialize interrupt handling.
2360Sstevel@tonic-gate */
2370Sstevel@tonic-gate oldhup = signal(SIGHUP, SIG_IGN);
2380Sstevel@tonic-gate if (oldhup == SIG_DFL)
2390Sstevel@tonic-gate signal(SIGHUP, onhup);
2400Sstevel@tonic-gate oldquit = signal(SIGQUIT, SIG_IGN);
2410Sstevel@tonic-gate ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL;
2420Sstevel@tonic-gate if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
2430Sstevel@tonic-gate signal(SIGTERM, onhup);
2440Sstevel@tonic-gate if (signal(SIGEMT, SIG_IGN) == SIG_DFL)
2450Sstevel@tonic-gate signal(SIGEMT, onemt);
2460Sstevel@tonic-gate signal(SIGILL, oncore);
2470Sstevel@tonic-gate signal(SIGTRAP, oncore);
2480Sstevel@tonic-gate signal(SIGIOT, oncore);
2490Sstevel@tonic-gate signal(SIGFPE, oncore);
2500Sstevel@tonic-gate signal(SIGBUS, oncore);
2510Sstevel@tonic-gate signal(SIGSEGV, oncore);
2520Sstevel@tonic-gate signal(SIGPIPE, oncore);
2530Sstevel@tonic-gate init_re();
2540Sstevel@tonic-gate while (1) {
2550Sstevel@tonic-gate #ifdef TRACE
2560Sstevel@tonic-gate while ((c = getopt(ac, (char **)av, "VU:Lc:Tvt:rlw:xRCsS")) !=
2570Sstevel@tonic-gate EOF)
2580Sstevel@tonic-gate #else
2590Sstevel@tonic-gate while ((c = getopt(ac, (char **)av,
260597Sceastha "VLc:vt:rlw:xRCsS")) != EOF)
2610Sstevel@tonic-gate #endif
2620Sstevel@tonic-gate switch (c) {
2630Sstevel@tonic-gate case 's':
2640Sstevel@tonic-gate hush = 1;
2650Sstevel@tonic-gate value(vi_AUTOPRINT) = 0;
2660Sstevel@tonic-gate fast++;
2670Sstevel@tonic-gate break;
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate case 'R':
2700Sstevel@tonic-gate value(vi_READONLY) = 1;
2710Sstevel@tonic-gate break;
2720Sstevel@tonic-gate case 'S':
2730Sstevel@tonic-gate tags_flag = 1;
2740Sstevel@tonic-gate break;
2750Sstevel@tonic-gate #ifdef TRACE
2760Sstevel@tonic-gate case 'T':
2770Sstevel@tonic-gate tracef = (unsigned char *)"trace";
2780Sstevel@tonic-gate goto trace;
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate case 'U':
2810Sstevel@tonic-gate tracef = tttrace;
2820Sstevel@tonic-gate strcpy(tracef, optarg);
2830Sstevel@tonic-gate trace:
2840Sstevel@tonic-gate trace = fopen((char *)tracef, "w");
2850Sstevel@tonic-gate #define tracbuf NULL
2860Sstevel@tonic-gate if (trace == NULL)
287802Scf46844 viprintf("Trace create error\n");
2880Sstevel@tonic-gate else
2890Sstevel@tonic-gate setbuf(trace, (char *)tracbuf);
2900Sstevel@tonic-gate break;
2910Sstevel@tonic-gate #endif
2920Sstevel@tonic-gate case 'c':
2930Sstevel@tonic-gate if (optarg != NULL)
2940Sstevel@tonic-gate firstpat = (unsigned char *)optarg;
2950Sstevel@tonic-gate else
2960Sstevel@tonic-gate firstpat = (unsigned char *)"";
2970Sstevel@tonic-gate break;
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate case 'l':
3000Sstevel@tonic-gate value(vi_LISP) = 1;
3010Sstevel@tonic-gate value(vi_SHOWMATCH) = 1;
3020Sstevel@tonic-gate break;
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate case 'r':
3050Sstevel@tonic-gate if (av[optind] && (c = av[optind][0]) &&
3060Sstevel@tonic-gate c != '-') {
3070Sstevel@tonic-gate if ((strlen(av[optind])) >=
3080Sstevel@tonic-gate sizeof (savedfile)) {
3090Sstevel@tonic-gate (void) fprintf(stderr, gettext(
310597Sceastha "Recovered file name"
311597Sceastha " too long\n"));
3120Sstevel@tonic-gate exit(1);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate rcvname = (unsigned char *)av[optind];
3160Sstevel@tonic-gate optind++;
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate case 'L':
3200Sstevel@tonic-gate recov++;
3210Sstevel@tonic-gate break;
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate case 'V':
3240Sstevel@tonic-gate verbose = 1;
3250Sstevel@tonic-gate break;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate case 't':
3280Sstevel@tonic-gate if (toptseen) {
3290Sstevel@tonic-gate usage(cmdnam);
3300Sstevel@tonic-gate exit(1);
3310Sstevel@tonic-gate } else {
3320Sstevel@tonic-gate toptseen++;
3330Sstevel@tonic-gate }
334*4488Scf46844 itag = tagflg = 1; /* -t option */
3350Sstevel@tonic-gate if (strlcpy(lasttag, optarg,
3360Sstevel@tonic-gate sizeof (lasttag)) >= sizeof (lasttag)) {
3370Sstevel@tonic-gate (void) fprintf(stderr, gettext("Tag"
3380Sstevel@tonic-gate " file name too long\n"));
3390Sstevel@tonic-gate exit(1);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate break;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate case 'w':
3440Sstevel@tonic-gate defwind = 0;
3450Sstevel@tonic-gate if (optarg[0] == NULL)
3460Sstevel@tonic-gate defwind = 3;
3470Sstevel@tonic-gate else for (cp = (unsigned char *)optarg;
3480Sstevel@tonic-gate isdigit(*cp); cp++)
3490Sstevel@tonic-gate defwind = 10*defwind + *cp - '0';
3500Sstevel@tonic-gate if (defwind < 0)
3510Sstevel@tonic-gate defwind = 3;
3520Sstevel@tonic-gate break;
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate case 'C':
3550Sstevel@tonic-gate crflag = 1;
3560Sstevel@tonic-gate xflag = 1;
3570Sstevel@tonic-gate break;
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate case 'x':
3600Sstevel@tonic-gate /* encrypted mode */
3610Sstevel@tonic-gate xflag = 1;
3620Sstevel@tonic-gate crflag = -1;
3630Sstevel@tonic-gate break;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate case 'v':
3660Sstevel@tonic-gate ivis = 1;
3670Sstevel@tonic-gate break;
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate default:
3700Sstevel@tonic-gate usage(cmdnam);
3710Sstevel@tonic-gate exit(1);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate if (av[optind] && av[optind][0] == '+' &&
3740Sstevel@tonic-gate av[optind-1] && strcmp(av[optind-1], "--")) {
375802Scf46844 firstpat = (unsigned char *)&av[optind][1];
3760Sstevel@tonic-gate optind++;
3770Sstevel@tonic-gate continue;
3780Sstevel@tonic-gate } else if (av[optind] && av[optind][0] == '-' &&
3790Sstevel@tonic-gate av[optind-1] && strcmp(av[optind-1], "--")) {
3800Sstevel@tonic-gate hush = 1;
3810Sstevel@tonic-gate value(vi_AUTOPRINT) = 0;
3820Sstevel@tonic-gate fast++;
3830Sstevel@tonic-gate optind++;
3840Sstevel@tonic-gate continue;
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate break;
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate
389597Sceastha if (isatty(0) == 0) {
390597Sceastha /*
391597Sceastha * If -V option is set and input is coming in via
392597Sceastha * stdin then vi behavior should be ignored. The vi
393597Sceastha * command should act like ex and only process ex commands
394597Sceastha * and echo the input ex commands to stderr
395597Sceastha */
396597Sceastha if (verbose == 1) {
397597Sceastha ivis = 0;
398597Sceastha }
399597Sceastha
400597Sceastha /*
401597Sceastha * If the standard input is not a terminal device,
402597Sceastha * it is as if the -s option has been specified.
403597Sceastha */
404597Sceastha if (ivis == 0) {
405597Sceastha hush = 1;
406597Sceastha value(vi_AUTOPRINT) = 0;
407597Sceastha fast++;
408597Sceastha }
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate ac -= optind;
4120Sstevel@tonic-gate av = &av[optind];
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate for (argcounter = 0; argcounter < ac; argcounter++) {
4150Sstevel@tonic-gate if ((strlen(av[argcounter])) >= sizeof (savedfile)) {
4160Sstevel@tonic-gate (void) fprintf(stderr, gettext("File argument"
417597Sceastha " too long\n"));
4180Sstevel@tonic-gate exit(1);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate #ifdef SIGTSTP
4230Sstevel@tonic-gate if (!hush && signal(SIGTSTP, SIG_IGN) == SIG_DFL)
4240Sstevel@tonic-gate signal(SIGTSTP, onsusp), dosusp++;
4250Sstevel@tonic-gate #endif
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate if (xflag) {
4280Sstevel@tonic-gate permflag = 1;
4290Sstevel@tonic-gate if ((kflag = run_setkey(perm,
4300Sstevel@tonic-gate (key = (unsigned char *)getpass(
4310Sstevel@tonic-gate gettext("Enter key:"))))) == -1) {
4320Sstevel@tonic-gate kflag = 0;
4330Sstevel@tonic-gate xflag = 0;
4340Sstevel@tonic-gate smerror(gettext("Encryption facility not available\n"));
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate if (kflag == 0)
4370Sstevel@tonic-gate crflag = 0;
4380Sstevel@tonic-gate else {
4390Sstevel@tonic-gate strcpy(cryptkey, "CrYpTkEy=XXXXXXXXX");
4400Sstevel@tonic-gate strcpy(cryptkey + 9, key);
4410Sstevel@tonic-gate if (putenv((char *)cryptkey) != 0)
4420Sstevel@tonic-gate smerror(gettext(" Cannot copy key to environment"));
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate #ifndef PRESUNEUC
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * Perform locale-specific initialization
4490Sstevel@tonic-gate */
450802Scf46844 localize();
4510Sstevel@tonic-gate #endif /* PRESUNEUC */
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate * Initialize end of core pointers.
4550Sstevel@tonic-gate * Normally we avoid breaking back to fendcore after each
4560Sstevel@tonic-gate * file since this can be expensive (much core-core copying).
4570Sstevel@tonic-gate * If your system can scatter load processes you could do
4580Sstevel@tonic-gate * this as ed does, saving a little core, but it will probably
4590Sstevel@tonic-gate * not often make much difference.
4600Sstevel@tonic-gate */
4610Sstevel@tonic-gate fendcore = (line *) sbrk(0);
4620Sstevel@tonic-gate endcore = fendcore - 2;
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate * If we are doing a recover and no filename
4660Sstevel@tonic-gate * was given, then execute an exrecover command with
4670Sstevel@tonic-gate * the -r option to type out the list of saved file names.
4680Sstevel@tonic-gate * Otherwise set the remembered file name to the first argument
4690Sstevel@tonic-gate * file name so the "recover" initial command will find it.
4700Sstevel@tonic-gate */
4710Sstevel@tonic-gate if (recov) {
4720Sstevel@tonic-gate if (ac == 0 && (rcvname == NULL || *rcvname == NULL)) {
4730Sstevel@tonic-gate ppid = 0;
4740Sstevel@tonic-gate setrupt();
4750Sstevel@tonic-gate execlp(EXRECOVER, "exrecover", "-r", (char *)0);
4760Sstevel@tonic-gate filioerr(EXRECOVER);
4770Sstevel@tonic-gate exit(++errcnt);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate if (rcvname && *rcvname)
4800Sstevel@tonic-gate (void) strlcpy(savedfile, rcvname, sizeof (savedfile));
4810Sstevel@tonic-gate else {
4820Sstevel@tonic-gate (void) strlcpy(savedfile, *av++, sizeof (savedfile));
4830Sstevel@tonic-gate ac--;
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate /*
4880Sstevel@tonic-gate * Initialize the argument list.
4890Sstevel@tonic-gate */
490802Scf46844 argv0 = (unsigned char **)av;
4910Sstevel@tonic-gate argc0 = ac;
492802Scf46844 args0 = (unsigned char *)av[0];
4930Sstevel@tonic-gate erewind();
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate * Initialize a temporary file (buffer) and
4970Sstevel@tonic-gate * set up terminal environment. Read user startup commands.
4980Sstevel@tonic-gate */
4990Sstevel@tonic-gate if (setexit() == 0) {
5000Sstevel@tonic-gate setrupt();
5010Sstevel@tonic-gate intty = isatty(0);
5020Sstevel@tonic-gate value(vi_PROMPT) = intty;
5030Sstevel@tonic-gate if (((cp = (unsigned char *)getenv("SHELL")) != NULL) &&
5040Sstevel@tonic-gate (*cp != '\0')) {
5050Sstevel@tonic-gate if (strlen(cp) < sizeof (shell)) {
5060Sstevel@tonic-gate (void) strlcpy(shell, cp, sizeof (shell));
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate if (fast)
510802Scf46844 setterm((unsigned char *)"dumb");
5110Sstevel@tonic-gate else {
5120Sstevel@tonic-gate gettmode();
5130Sstevel@tonic-gate cp = (unsigned char *)getenv("TERM");
5140Sstevel@tonic-gate if (cp == NULL || *cp == '\0')
5150Sstevel@tonic-gate cp = (unsigned char *)"unknown";
5160Sstevel@tonic-gate setterm(cp);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate /*
5210Sstevel@tonic-gate * Bring up some code from init()
5220Sstevel@tonic-gate * This is still done in init later. This
5230Sstevel@tonic-gate * avoids null pointer problems
5240Sstevel@tonic-gate */
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate dot = zero = truedol = unddol = dol = fendcore;
5270Sstevel@tonic-gate one = zero+1;
5280Sstevel@tonic-gate {
529802Scf46844 int i;
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate for (i = 0; i <= 'z'-'a'+1; i++)
5320Sstevel@tonic-gate names[i] = 1;
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate if (setexit() == 0 && !fast) {
5360Sstevel@tonic-gate if ((globp =
537597Sceastha (unsigned char *) getenv("EXINIT")) && *globp) {
5380Sstevel@tonic-gate if (ivis)
5390Sstevel@tonic-gate inexrc = 1;
5400Sstevel@tonic-gate commands(1, 1);
5410Sstevel@tonic-gate inexrc = 0;
5420Sstevel@tonic-gate } else {
5430Sstevel@tonic-gate globp = 0;
5440Sstevel@tonic-gate if ((cp = (unsigned char *) getenv("HOME")) !=
5450Sstevel@tonic-gate 0 && *cp) {
5460Sstevel@tonic-gate strncpy(scratch, cp, sizeof (scratch) - 1);
5470Sstevel@tonic-gate strncat(scratch, "/.exrc",
5480Sstevel@tonic-gate sizeof (scratch) - 1 - strlen(scratch));
5490Sstevel@tonic-gate if (ivis)
550597Sceastha inexrc = 1;
5510Sstevel@tonic-gate if ((vret = validate_exrc(scratch)) == 0) {
5520Sstevel@tonic-gate source(scratch, 1);
5530Sstevel@tonic-gate } else {
5540Sstevel@tonic-gate if (vret == -1) {
5550Sstevel@tonic-gate error(gettext(
5560Sstevel@tonic-gate "Not owner of .exrc "
5570Sstevel@tonic-gate "or .exrc is group or "
5580Sstevel@tonic-gate "world writable"));
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate inexrc = 0;
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate /*
5660Sstevel@tonic-gate * Allow local .exrc if the "exrc" option was set. This
5670Sstevel@tonic-gate * loses if . is $HOME, but nobody should notice unless
5680Sstevel@tonic-gate * they do stupid things like putting a version command
5690Sstevel@tonic-gate * in .exrc.
5700Sstevel@tonic-gate * Besides, they should be using EXINIT, not .exrc, right?
5710Sstevel@tonic-gate */
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate if (value(vi_EXRC)) {
5740Sstevel@tonic-gate if (ivis)
5750Sstevel@tonic-gate inexrc = 1;
5760Sstevel@tonic-gate if ((cp = (unsigned char *) getenv("PWD")) != 0 &&
5770Sstevel@tonic-gate *cp) {
5780Sstevel@tonic-gate strncpy(exrcpath, cp, sizeof (exrcpath) - 1);
5790Sstevel@tonic-gate strncat(exrcpath, "/.exrc",
5800Sstevel@tonic-gate sizeof (exrcpath) - 1 - strlen(exrcpath));
5810Sstevel@tonic-gate if (strcmp(scratch, exrcpath) != 0) {
5820Sstevel@tonic-gate if ((vret =
5830Sstevel@tonic-gate validate_exrc(exrcpath)) == 0) {
5840Sstevel@tonic-gate source(exrcpath, 1);
5850Sstevel@tonic-gate } else {
5860Sstevel@tonic-gate if (vret == -1) {
5870Sstevel@tonic-gate error(gettext(
5880Sstevel@tonic-gate "Not owner of "
5890Sstevel@tonic-gate ".exrc or .exrc "
5900Sstevel@tonic-gate "is group or world "
5910Sstevel@tonic-gate "writable"));
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate inexrc = 0;
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate init(); /* moved after prev 2 chunks to fix directory option */
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate * Initial processing. Handle tag, recover, and file argument
6040Sstevel@tonic-gate * implied next commands. If going in as 'vi', then don't do
6050Sstevel@tonic-gate * anything, just set initev so we will do it later (from within
6060Sstevel@tonic-gate * visual).
6070Sstevel@tonic-gate */
6080Sstevel@tonic-gate if (setexit() == 0) {
6090Sstevel@tonic-gate if (recov)
6100Sstevel@tonic-gate globp = (unsigned char *)"recover";
6110Sstevel@tonic-gate else if (itag) {
6120Sstevel@tonic-gate globp = ivis ? (unsigned char *)"tag" :
6130Sstevel@tonic-gate (unsigned char *)"tag|p";
6140Sstevel@tonic-gate #ifdef XPG4
6150Sstevel@tonic-gate if (firstpat != NULL) {
6160Sstevel@tonic-gate /*
6170Sstevel@tonic-gate * if the user specified the -t and -c
6180Sstevel@tonic-gate * flags together, then we service these
6190Sstevel@tonic-gate * commands here. -t is handled first.
6200Sstevel@tonic-gate */
6210Sstevel@tonic-gate savepat = firstpat;
6220Sstevel@tonic-gate firstpat = NULL;
6230Sstevel@tonic-gate inglobal = 1;
6240Sstevel@tonic-gate commands(1, 1);
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate /* now handle the -c argument: */
6270Sstevel@tonic-gate globp = savepat;
6280Sstevel@tonic-gate commands(1, 1);
6290Sstevel@tonic-gate inglobal = 0;
6300Sstevel@tonic-gate globp = savepat = NULL;
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /* the above isn't sufficient for ex mode: */
6330Sstevel@tonic-gate if (!ivis) {
6340Sstevel@tonic-gate setdot();
6350Sstevel@tonic-gate nonzero();
6360Sstevel@tonic-gate plines(addr1, addr2, 1);
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate #endif /* XPG4 */
6400Sstevel@tonic-gate } else if (argc)
6410Sstevel@tonic-gate globp = (unsigned char *)"next";
6420Sstevel@tonic-gate if (ivis)
6430Sstevel@tonic-gate initev = globp;
6440Sstevel@tonic-gate else if (globp) {
6450Sstevel@tonic-gate inglobal = 1;
6460Sstevel@tonic-gate commands(1, 1);
6470Sstevel@tonic-gate inglobal = 0;
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate /*
6520Sstevel@tonic-gate * Vi command... go into visual.
6530Sstevel@tonic-gate */
6540Sstevel@tonic-gate if (ivis) {
6550Sstevel@tonic-gate /*
6560Sstevel@tonic-gate * Don't have to be upward compatible
6570Sstevel@tonic-gate * by starting editing at line $.
6580Sstevel@tonic-gate */
6590Sstevel@tonic-gate #ifdef XPG4
6600Sstevel@tonic-gate if (!itag && (dol > zero))
6610Sstevel@tonic-gate #else /* XPG4 */
6620Sstevel@tonic-gate if (dol > zero)
6630Sstevel@tonic-gate #endif /* XPG4 */
6640Sstevel@tonic-gate dot = one;
6650Sstevel@tonic-gate globp = (unsigned char *)"visual";
6660Sstevel@tonic-gate if (setexit() == 0)
6670Sstevel@tonic-gate commands(1, 1);
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate /*
6710Sstevel@tonic-gate * Clear out trash in state accumulated by startup,
6720Sstevel@tonic-gate * and then do the main command loop for a normal edit.
6730Sstevel@tonic-gate * If you quit out of a 'vi' command by doing Q or ^\,
6740Sstevel@tonic-gate * you also fall through to here.
6750Sstevel@tonic-gate */
6760Sstevel@tonic-gate seenprompt = 1;
6770Sstevel@tonic-gate ungetchar(0);
6780Sstevel@tonic-gate globp = 0;
6790Sstevel@tonic-gate initev = 0;
6800Sstevel@tonic-gate setlastchar('\n');
6810Sstevel@tonic-gate setexit();
6820Sstevel@tonic-gate commands(0, 0);
6830Sstevel@tonic-gate cleanup(1);
684802Scf46844 return (errcnt);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate * Initialization, before editing a new file.
6890Sstevel@tonic-gate * Main thing here is to get a new buffer (in fileinit),
6900Sstevel@tonic-gate * rest is peripheral state resetting.
6910Sstevel@tonic-gate */
692802Scf46844 void
init(void)693802Scf46844 init(void)
6940Sstevel@tonic-gate {
695802Scf46844 int i;
6960Sstevel@tonic-gate void (*pstat)();
6970Sstevel@tonic-gate fileinit();
6980Sstevel@tonic-gate dot = zero = truedol = unddol = dol = fendcore;
6990Sstevel@tonic-gate one = zero+1;
7000Sstevel@tonic-gate undkind = UNDNONE;
7010Sstevel@tonic-gate chng = 0;
7020Sstevel@tonic-gate edited = 0;
7030Sstevel@tonic-gate for (i = 0; i <= 'z'-'a'+1; i++)
7040Sstevel@tonic-gate names[i] = 1;
7050Sstevel@tonic-gate anymarks = 0;
7060Sstevel@tonic-gate if (xflag) {
7070Sstevel@tonic-gate xtflag = 1;
7080Sstevel@tonic-gate /* ignore SIGINT before crypt process */
7090Sstevel@tonic-gate pstat = signal(SIGINT, SIG_IGN);
7100Sstevel@tonic-gate if (tpermflag)
7110Sstevel@tonic-gate (void) crypt_close(tperm);
7120Sstevel@tonic-gate tpermflag = 1;
7130Sstevel@tonic-gate if (makekey(tperm) != 0) {
7140Sstevel@tonic-gate xtflag = 0;
7150Sstevel@tonic-gate smerror(gettext(
7160Sstevel@tonic-gate "Warning--Cannot encrypt temporary buffer\n"));
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate signal(SIGINT, pstat);
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate * Return last component of unix path name p.
7240Sstevel@tonic-gate */
7250Sstevel@tonic-gate unsigned char *
tailpath(p)7260Sstevel@tonic-gate tailpath(p)
727802Scf46844 unsigned char *p;
7280Sstevel@tonic-gate {
729802Scf46844 unsigned char *r;
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate for (r = p; *p; p++)
7320Sstevel@tonic-gate if (*p == '/')
7330Sstevel@tonic-gate r = p+1;
7340Sstevel@tonic-gate return (r);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate * validate_exrc - verify .exrc as belonging to the user.
7400Sstevel@tonic-gate * The file uid should match the process ruid,
7410Sstevel@tonic-gate * and the file should be writable only by the owner.
7420Sstevel@tonic-gate */
7430Sstevel@tonic-gate static int
validate_exrc(unsigned char * exrc_path)7440Sstevel@tonic-gate validate_exrc(unsigned char *exrc_path)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate struct stat64 exrc_stat;
7470Sstevel@tonic-gate int process_uid;
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate if (stat64((char *)exrc_path, &exrc_stat) == -1)
7500Sstevel@tonic-gate return (0); /* ignore if .exrec is not found */
7510Sstevel@tonic-gate process_uid = geteuid();
7520Sstevel@tonic-gate /* if not root, uid must match file owner */
7530Sstevel@tonic-gate if (process_uid && process_uid != exrc_stat.st_uid)
7540Sstevel@tonic-gate return (-1);
7550Sstevel@tonic-gate if ((exrc_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
7560Sstevel@tonic-gate return (-1);
7570Sstevel@tonic-gate return (0);
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate /*
7610Sstevel@tonic-gate * print usage message to stdout
7620Sstevel@tonic-gate */
7630Sstevel@tonic-gate static void
usage(unsigned char * name)7640Sstevel@tonic-gate usage(unsigned char *name)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate char buf[160];
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate #ifdef TRACE
7690Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext(
770597Sceastha "Usage: %s [- | -s] [-l] [-L] [-wn] "
771597Sceastha "[-R] [-S] [-r [file]] [-t tag] [-T] [-U tracefile]\n"
772597Sceastha "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name);
7730Sstevel@tonic-gate #else
7740Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext(
775597Sceastha "Usage: %s [- | -s] [-l] [-L] [-wn] "
776597Sceastha "[-R] [-S] [-r [file]] [-t tag]\n"
777597Sceastha "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name);
7780Sstevel@tonic-gate #endif
7790Sstevel@tonic-gate (void) write(2, buf, strlen(buf));
7800Sstevel@tonic-gate }
781