geoff@callan.UUCP (09/05/84)
: This is a shar archive. Extract with sh, not csh. : The rest of this file will extract: : : README Makefile edstart.1 edstart.c : echo extracting - README sed 's/^-//' > README << '/*EOF' Well, I really liked the idea of Dolf Starreveld's VISTARTUP program, which sets up EXINIT based on your extension. Unfortunately, I'm not a vi user. So I hacked Dolf's program up to allow arbitrary editors, as well as adding a feature or two (one of which I haven't actually implemented yet). Since I'm not a vi user, the example at the end of the manual page is a bit weak. I sure would appreciate it if one of you kind folks out there could send me a more realistic one. In particular, I think it needs a separator character in the first line of the .editrc file. Also, note that this program looks for an .editrc file in the current directory as well as the home one, but does not check ownership of same. If this is too much of a security hole for you, you should compile with the SECURE option. Geoff Kuenning ...!ihnp4!wlbr!desint!geoff /*EOF echo extracting - Makefile sed 's/^-//' > Makefile << '/*EOF' # # @(#)Makefile 1.2 9/1/84 18:42:25 # # Define USG if you have strchr/strrchr instead of index/rindex. # Define SECURE if you don't want to look in the current directory # for the .editrc file. # CFLAGS= -v -DUSG -O /*EOF echo extracting - edstart.1 sed 's/^-//' > edstart.1 << '/*EOF' .TH EDSTART 1 .UC 4 .SH NAME edstart \- start an editor with special options .SH SYNOPSIS .B edstart [ .B editor options ] .br .SH DESCRIPTION .I Edstart reads lines from the file ".editrc" in either the current directory or the users HOME directory and examines the file arguments given to this program. After this the real editor is started, essentially leaving all arguments to the editor intact. Depending on the extensions of the file arguments, commands are executed as specified in the .editrc file. .PP Fields on each line of the .editrc file are separated by colons. The colons may be escaped with a backslash if necessary. No other escaping is needed, except for backslashes themselves. Blank lines are allowed, as long as they contain no whitespace. Comment lines are marked by a '#' character in the first column. .PP The first line of the .editrc file has the following format: .br <editor>:<variable>:<separator>:<terminator>:<getopt string> .br The editor field gives the full pathname of the editor for exec's. .PP The variable field gives the name of the environment variable to be changed for editor initialization. This field must include the equals sign; for example, "EXINIT=". .PP The separator string will be appended to any previous value of the environment variable before commands associated with an extension are added. .PP The terminator string is appended to the environment variable following the newly-appended commands. If the terminator string is found at the end of the environment variable, it will be removed before any commands are appended to it. .PP The options field gives a getopt(3) string defining arguments to the editor in use. As an extension for use with vi, if the option string begins with the character "+", options beginning with "+" will also be accepted. .PP All subsequent lines of the file have the following format: .br <extension>:<priority>:<switches>:<editor commands> .br Blanks are not allowed in the first field, which ends at the first colon. .PP The extension field defines the extension for which the commands in the third field wil be executed. This field does not include the period, i.e. for C source files it will be a single letter "c". Every character up to but not including the first colon is made part of the extension, this being the reason for blanks being forbidden in this field. A null extension applies to files which have no extension. .PP As a special case, if the last line of the file has an extension field of "." (which is impossible as a file extension), this line will be taken as a default line which applies to any file unmatched by other lines. .PP The switches field gives switches or arguments to be added to the editor command line. However, this field is not currently implemented. .PP When several files with different extensions are used, the prefered settings are determined as follows. Each time a file is seen with an extension specified in the .editrc file, the value defined in the priority field will be added to a total, maintained per extension. After all files have been examined, the command(s) on the lines for the extension which now has the largest total count, are executed. If you don't want these priorities, simply define all priority fields to be zero. In that case the commands corresponding to the extension of the first file argument will be used. .PP Once the commands to execute are known, the environment is altered. If the editor-initialization variable was already present, the specified commands are concatenated to the value of the editor-initialization variable, with a colon before it. If the environment variable was undefined, it is added to the environment. When the new environment is ready, the program execs itself with the editor specified in the .editrc file, which thus inherits the new environment. .PP The result of the use of the editor-initialization variable by this program is that when working in progressively deeper nested shells, the value of the variable will increase in length. It also means that no command as specified in the list in the .editrc file may rely on any default setting of options of the editor, because these may already have been altered by previous invocations of the editor. .SH EXAMPLES The following example shows how the program might be used with the 'vi' editor: .nf -/bin/vi|EXINIT=|||+t:rw: c|5||set magic showmatch |0||set magic .|0||set nomagic .fi This causes the .I magic and .I showmatch options of the .I vi editor to be selected for C-language source files, the .I magic option to be selected for files with no extension, and the .I nomagic option to be selected for all other files. If the editor is invoked with more than one file and one of them is a C source file, the C options will take priority. .SH "SEE ALSO" ex(1) .SH BUGS The switches field is unimplemented. .SH AUTHOR Geoff Kuenning. Based on the program "vistartup" by Dolf Starreveld, University of Amsterdam .\" @(#)edstart.1 1.1 9/1/84 18:21:32 /*EOF echo extracting - edstart.c sed 's/^-//' > edstart.c << '/*EOF' static char Sccs_Id[] = "@(#)edstart.c 1.2 9/1/84 18:42:29"; -/* * EDSTARTUP * * Author: Geoff Kuenning * Hacked from the program VISTARTUP, by * Dolf Starreveld, University of Amsterdam. * * * This program is a startup program for any editor. * It runs under Unix System V and I think it will run * on most other versions of Unix. * The original program (by Dolf Starreveld) was designed * after reading the disussion on the net about the advantages * and disadvantages of mode lines, as available in ex/vi 3.7. * The security danger of mode lines is avoided by using this * program, keeping only the good things of mode lines. * The hacked version was created to support other editors * than vi. * * The programs scans a special formatted file in the users home * directory, ".editrc". In this file commands may be placed that * are added to the command arguments and to the appropriate * environment variable (EXINIT for vi) for the execution * of this command only. For details see the manual page. * */ #include <stdio.h> int main (); /* Set editor environment from args */ static void filltab (); /* Fill extension-action table */ static char * getfld (); /* Get a field from the table */ static int extens (); /* Extract an extension */ static void fatal (); /* Issue a fatal error */ #ifdef USG #define index strchr #define rindex strrchr #endif #define MAXENV 256 /* Maximum number of environment variables */ #define INITLEN 512 /* Longest acceptable environment variable */ #define MAXEXTS 250 /* Maximum number of ext. lines in eatab */ #define SOURCE "/.editrc" /* Must contain a slash - see filltab */ #define option(c) ((c == '-') || (vioptions && c == '+')) static char * editor = "/bin/vi"; /* Editor to be used */ static char * envvar; /* Environment variable to modify */ static char * newenv[MAXENV]; static char ** newenvp = &newenv[0]; static char newinit[INITLEN]; static char ** oldenv; static char * optstr; static char * prog = "edstartup"; static char * separator; /* Separator between command strings */ static int tabentries = 0; static char * terminator; /* Terminator for command strings */ static int vioptions = 0; /* Nonzero if vi options (+-type) in effect */ static struct ext_act /* Commands to do for each extension */ { char * ext; /* Extension */ char * act; /* Required command */ char * switches; /* Switches to add to command line */ int prior; /* Per file priority value */ int tprior; /* Total priority during after argument scan */ } eatab[MAXEXTS]; extern char * getenv (); extern char * index (); extern char * malloc (); extern char * rindex (); int main (argc, argv, envp) int argc; /* Argument count */ register char * argv[]; /* Argument vector */ register char * envp[]; /* Environment vector */ { char ** args; /* Arguments to pass to editor */ register int extension; /* Index into eatab */ int initdone = 0; /* Nonzero if EXINIT (or such) seen */ int maxext = -1; /* Index of high-priority extension */ int maxprior = -1; /* Priority of high-pri ext */ register char * scratchp; /* Handy scratch pointer */ filltab (); args = argv; oldenv = envp; if (argc > 0) { prog = rindex (argv[0], '/'); if (prog == NULL) prog = argv[0]; } /* Skip all options */ while (argv++, --argc > 0 && option (argv[0][0])) { if (argv[0][0] == '+') /* Kludge for good ol' vi */ continue; if (argv[0][1] == '-' /* End of options? */ || argv[0][1] == '\0') /* - is a file name (stdin) */ { argc--; /* Skip this one too */ argv++; break; } if ((scratchp = index (optstr, argv[0][1])) != NULL) if (scratchp[1] == ':') /* Does switch take an arg? */ if (argv[0][2] == '\0') /* If so, eat it */ { argc--; argv++; } } -/* If there are no file arguments, use the default entry. */ if (argc <= 0 /* No file arguments? */ && strcmp (eatab[tabentries - 1].ext, ".") == 0) maxext = tabentries - 1; while (argc--) /* Process file arguments */ { /* Find extension index */ extension = extens (*argv++); if (extension != -1) /* Known ext, add to total */ { eatab[extension].tprior += eatab[extension].prior; if (eatab[extension].tprior > maxprior) { maxprior = eatab[extension].tprior; maxext = extension; } } } /* * All filename arguments are processed. The extension with * largest total priority is now known, so add its action * as last part of the EXINIT string. * If EXINIT was not defined, add it to the environment. * If no files were given or no extension was recognized, do * nothing. */ if (maxext != -1) { -/* char * switches; /* Switches to add to command line */ while (*envp) /* Copy complete environment */ { if (strncmp (envvar, *envp, strlen (envvar)) == 0) { strcpy (newinit, *envp); scratchp = &newinit[strlen (newinit)]; scratchp -= strlen (terminator); if (strcmp (scratchp, terminator) == 0) *scratchp = 0; /* Get rid of any terminator */ scratchp = &newinit[strlen (newinit)]; scratchp -= strlen (separator); if (strcmp (scratchp, separator) == 0) *scratchp = 0; /* Get rid of any separator */ strcat (newinit, separator); strcat (newinit, eatab[maxext].act); strcat (newinit, terminator); *envp = newinit; initdone = 1; } *newenvp++ = *envp++; } if (!initdone) { strcpy (newinit, envvar); strcat (newinit, eatab[maxext].act); strcat (newinit, terminator); *newenvp++ = newinit; } *newenvp = NULL; } /* * The new environment list is now ready, exec the thing. */ /* Install program name */ *args = rindex (editor, '/'); if (*args == NULL) *args = editor; else (*args)++; execve (editor, args, (maxext == -1 ? oldenv : newenv)); fatal ("Cannot exec %s.\n", args[0]); } static void filltab () { FILE * fd; /* File descriptor for table */ char linbuf[512]; /* Buffer for control lines */ char * line; /* Pointer into linbuf */ register int nr; /* Index into eatab */ linbuf[0] = '\0'; if ((line = getenv ("HOME")) != NULL) strcpy (linbuf, line); strcat (linbuf, SOURCE); nr = 0; #ifdef SECURE if ((fd = fopen (linbuf, "r")) == NULL) #else -/* The following rindex is guaranteed to return a non-null value, because SOURCE contains a slash. */ if ((fd = fopen (rindex (linbuf, '/') + 1, "r")) == NULL && (fd = fopen (linbuf, "r")) == NULL) #endif fatal ("Couldn't open %s file\n", SOURCE); else { -/* Header line: <editor>|<variable>|<separator>|<terminator>|<getopt string> */ while (fgets (linbuf, sizeof linbuf, fd) != NULL) { if (linbuf[0] == '#' || linbuf[0] == '\n') continue; line = linbuf; editor = getfld (&line); envvar = getfld (&line); separator = getfld (&line); terminator = getfld (&line); optstr = getfld (&line); if (*optstr == '+') /* VI options mode? */ { vioptions = 1; optstr++; } break; } -/* <extension>|<priority>|<switches>|<editor commands> */ while (fgets (linbuf, sizeof linbuf, fd) != NULL) { if (linbuf[0] == '#' || linbuf[0] == '\n') continue; line = linbuf; eatab[nr].ext = getfld (&line); /* Extension */ eatab[nr].act = getfld (&line); /* A fake! Actually priority */ eatab[nr].prior = atoi (eatab[nr].act); free (eatab[nr].act); eatab[nr].tprior = 0; eatab[nr].switches = getfld(&line); /* Switches to add to cmd */ eatab[nr].act = getfld(&line); /* Cmds to add to envvar */ nr++; } fclose (fd); } tabentries = nr; } static char * getfld (buffer) char ** buffer; /* Pointer to buffer pointer */ /* ..ARGUMENT IS MODIFIED */ { register char * first; /* First character of field */ register char * fldbuf; /* Buffer for the field */ register char * fldcur; /* Next character in fldbuf */ register char * last; /* Last character + 1 of field */ if ((first = *buffer) == NULL) fatal ("Internal error in getfld", 0); if (*first == '\0') fatal ("Illegal format of %s file\n", SOURCE); while (1) { if ((last = index (first, '|')) == NULL && (last = index (first, '\n')) == NULL) fatal ("Illegal format of %s file\n", SOURCE); if (last == first || last[0] == '\n' || last[-1] != '\\' || (last - 1 > first && last[-2] == '\\')) break; /* We get here only if last points to the | of a \| sequence */ first = last + 1; } first = *buffer; /* Re-initialize first */ if ((fldbuf = malloc (last - first + 1)) == NULL) fatal ("Out of memory space for tables\n", 0); for (fldcur = fldbuf; first != last; ) { if (first[0] == '\\' && (first[1] == '|' || first[1] == '\\')) first++; *fldcur++ = *first++; } *fldcur = '\0'; *buffer = last + 1; /* Return pointer past separator */ return fldbuf; } static int extens (path) register char * path; { register int i; register int j; register char * ex; if ((ex = rindex (path, '.')) == NULL) ex = ""; else ex++; for (j = 0; j < tabentries; j++) if (strcmp (eatab[j].ext, ex) == 0) return (j); -/* If the last entry in the table has an extension of "." (which is impossible to get at the end of the file), use it as the default value for all other files. */ j--; if (strcmp (eatab[j].ext, ".") == 0) return (j); else return (-1); } static void fatal (s1, s2, s3, s4) int * s1; int * s2; int * s3; int * s4; { fprintf (stderr, "%s: ", prog); fprintf (stderr, s1, s2, s3, s4); fprintf (stderr, "\n"); exit (1); } /*EOF exit -- Geoff Kuenning Callan Data Systems ...!ihnp4!wlbr!callan!geoff ...!ihnp4!wlbr!desint!geoff