allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (03/22/89)
Posting-number: Volume 6, Issue 71 Submitted-by: tcjones@watdragon.waterloo.edu (speedboat jones) Archive-name: m [It's easier to shoot such people on sight -- or "unalias m" as your first action. I don't use alias abbreviations, since their interpretation is always open to question and I have to deal with some 30 systems on a day- to-day basis, sharing an alias file with at least two other people. ++bsa] Here is an extremely silly thing called "m". Isn't frustrating how some people alias m for mail, others use m for more, and some even use it for man? So that when you type at their terminal when they have their backs turned you can never get anything right? M is a more/mail/make/man thing. You just use m instead of any of those four and it attempts to figure out what you meant and execute the appropriate thing for you. It usually gets it right and if not, well, you can't be hurt too much. And you can always use the real command. This, of course, does not solve the above problem, so I suggest that everyone who uses this program changes their prompt to I-Use-M: so that the rest of the world will know. Whatever. Have fun etc. This will need a few changes to work on non-BSD systems I think. Here is (sort of) what happens... You type: m thinks: --------------------------------------------- unix_command | m more m mail (if there is recent mail)... ELSE make (if there is a Makefile or makefile)... ELSE mail m X more X (if X is an ordinary file.) ELSE... mail X (if X is a user name or mail alias). ELSE... make X (if X is a makefile target). man X. m A, B... mail A, B... m x X man x X (if x is a manual section and X a manpage) m -f mail -f m -f X mail -f X (if X is an ordinary file). m -k X man -k X Terry Jones Department Of Computer Science, University Of Waterloo Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674 UUCP: ...!watmath!watdragon!tcjones CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu} BITNET: tcjones@WATER.bitnet Canadian domain: tcjones@dragon.uwaterloo.ca #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 1)." # Contents: m m/Makefile m/README m/m.c m/tags # Wrapped by tcjones@watdragon on Wed Mar 15 13:01:48 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test ! -d 'm' ; then echo shar: Creating directory \"'m'\" mkdir 'm' fi if test -f 'm/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'m/Makefile'\" else echo shar: Extracting \"'m/Makefile'\" \(43 characters\) sed "s/^X//" >'m/Makefile' <<'END_OF_FILE' CFLAGS = -O X m: m.o X cc $(CFLAGS) -o m m.o END_OF_FILE if test 43 -ne `wc -c <'m/Makefile'`; then echo shar: \"'m/Makefile'\" unpacked with wrong size! fi # end of 'm/Makefile' fi if test -f 'm/README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'m/README'\" else echo shar: Extracting \"'m/README'\" \(1835 characters\) sed "s/^X//" >'m/README' <<'END_OF_FILE' X Here is an extremely silly thing called "m". Isn't frustrating how some people alias m for mail, others use m for more, and some even use it for man? So that when you type at their terminal when they have their backs turned you can never get anything right? X M is a more/mail/make/man thing. You just use m instead of any of those four and it attempts to figure out what you meant and execute the appropriate thing for you. It usually gets it right and if not, well, you can't be hurt too much. And you can always use the real command. X This, of course, does not solve the above problem, so I suggest that everyone who uses this program changes their prompt to I-Use-M: so that the rest of the world will know :-) X Whatever. Have fun etc. X X Here is (sort of) what happens... X You type: m thinks: X--------------------------------------------- unix_command | m more X m mail (if there is recent mail)... ELSE X make (if there is a Makefile or makefile)... ELSE X mail X m X more X (if X is an ordinary file.) ELSE... X mail X (if X is a user name or mail alias). ELSE... X make X (if X is a makefile target). X man X. X m A, B... mail A, B... m x X man x X (if x is a manual section and X a manpage) m -f mail -f m -f X mail -f X (if X is an ordinary file). m -k X man -k X X X X X Terry Jones X X Department Of Computer Science, University Of Waterloo X Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674 X UUCP: ...!watmath!watdragon!tcjones X CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu} X BITNET: tcjones@WATER.bitnet X Canadian domain: tcjones@dragon.uwaterloo.ca END_OF_FILE if test 1835 -ne `wc -c <'m/README'`; then echo shar: \"'m/README'\" unpacked with wrong size! fi # end of 'm/README' fi if test -f 'm/m.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'m/m.c'\" else echo shar: Extracting \"'m/m.c'\" \(8315 characters\) sed "s/^X//" >'m/m.c' <<'END_OF_FILE' X/* X * m.c -- man/mail/make/more guesswork. X * X * Invoke one of the above four by looking at our arguments and deciding X * which is the appropriate one. Has limitations but is fun... X * X * Terry Jones X * X * ----------------------------------------------------------------------------- X * Department Of Computer Science, University Of Waterloo X * Waterloo Ontario Canada N2L 3G1 X * X * {ihnp4,allegra,decvax,utzoo,utcsri,clyde}!watmath!watdragon!tcjones X * tcjones@dragon.waterloo.{cdn,edu} tcjones@WATER.bitnet X * tcjones%watdragon@waterloo.csnet X * ----------------------------------------------------------------------------- X */ X X#include <stdio.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/time.h> X X/* Some laziness to make things clearer(?) down below */ X X#define MORE go(more, ARGS) X#define MAN go("man", ARGS) X#define MAIL go("mail", ARGS) X#define MAKE go("make", ARGS) X X#define BIG 4096 X X/* More laziness. ARGn means "original argument n" X * RARGn means "real (non-option) argument n" X * X * Options are assumed to come first on the command line and to start with '-' X * X */ X X#define ARGS orig_argv X#define ARG0 (*orig_argv) X#define ARG1 (*(orig_argv+1)) X#define RARG0 (*argv) X#define RARG1 (*(argv+1)) X X/* Sections of the manual that we can recognize. */ X#define MANSECTIONS "0123456789cinopt" X X/* Mail is "new" if less than this number of seconds old. */ X#define NEW_MAIL 120 X extern char *getenv(); extern char *index(); extern FILE *openfile(); X char *myname; char *more; X main(argc, argv) int argc; char **argv; X{ X /* Save the original argument list and count. */ X register char **orig_argv = argv; X register int orig_argc = argc; X X myname = *argv; X X argc--; X argv++; X X /* Skip option arguments. */ X while (**argv == '-'){ X argv++; X argc--; X } X X if (!(more = getenv("PAGER"))) more = "more"; X X /* X * argc now hold the number of non-option arguments, argv points X * to the first non-option argument. X * X * The order in which we do the following tests will make an efficiency X * difference - try to do more likely and faster tests first. X * X */ X X if (argc == 0 && isatty(0) == 0) MORE; X if (argc == 0 && recent_mail()) MAIL; X if (argc == 0 && makefile()) MAKE; X if (argc == 1 && is_ord_file(RARG0)) MORE; X if (argc > 0 && hascomma(RARG0, RARG1)) MAIL; X if (argc == 0) MAIL; X if (argc == 1 && is_userid(RARG0)) MAIL; X if (argc == 1 && is_mailalias(RARG0)) MAIL; X if (argc == 2 && is_manpage(RARG0, RARG1)) MAN; X if (orig_argc == 2 && is_minus('f', ARG1)) MAIL; X if (orig_argc == 3 && is_minus('f', ARG1) && is_ord_file(RARG0)) MAIL; X if (argc == 1 && is_maketarget(RARG0)) MAKE; X if (orig_argc == 3 && is_minus('k', ARG1)) MAN; X if (argc == 1 && is_sysmailalias(RARG0)) MAIL; X if (argc == 1) MAN; X X X /* Give up. */ X printf("%s: Couldn't decide what to do!\n", myname); X exit(1); X} X go(s, args) char *s; char **args; X{ X /* Exec the command passed in using s, with all the original arguments. */ X X register char **tmp; X *args = s; X /* X * We could print the new command but it doesn't seem necessary - X * the result should make it obvious what we have done. X * X * tmp = args; X * while(**tmp) printf("%s ", *tmp++); X * putc('\n', stdout); X */ X X execvp(s, args); X printf(stderr, "%s: Could not execvp %s\n", myname, s); X exit(1); X} X X is_ord_file(s) char *s; X{ X /* Check to see if "s" is an ordinary file. */ X /* i.e. not a directory etc. */ X /* if it is executable and also a maketarget then return 0 & it gets made */ X X struct stat sbuf; X X if (stat(s, &sbuf) == -1) return 0; X if (sbuf.st_mode & S_IFMT != S_IFREG) return 0; X if ((sbuf.st_mode & S_IEXEC) && is_maketarget(s)) return 0; X return 1; X} X hascomma(s1, s2) char *s1; char *s2; X{ X /* X * Check to see if either s1 or s2 has a comma. This would seem to X * imply that the arguments are a comma separated list for mail. X * X */ X X return index(s1, ',') != NULL || index(s2, ',') != NULL; X} X makefile() X{ X /* Check to see if there is a makefile of some description. */ X X struct stat sbuf; X return stat("Makefile", &sbuf) == 0 || stat("makefile", &sbuf) == 0; X} X is_minus(flag, s) char flag; char *s; X{ X /* X * Check if "s" is the option given by the flag "flag". X * This could be a #define, and so could lots of the next few things. X * X * But they're ugly. X * X */ X X return s[0] == '-' && s[1] == flag && s[2] =='\0'; X} X X is_userid(s) char *s; X{ X /* X * Is "s" a userid? X * Look for a '@' or a '!' for a remote person, or X * check /u/"s" to find out locally. X * X */ X X struct passwd *getpwnam(); X X if (index(s, '!') || index(s, '@')) return 1; X return getpwnam(s) != NULL; X} X recent_mail() X{ X /* X * See if there is mail which has arrived in the last NEW_MAIL seconds. X * This could be much better. It could include a check to see if the X * mailbox was touched before you logged on and after your previous X * logoff - but who wants to read backwards through /usr/adm/wtmp ?? X * X */ X X char mail[BIG]; X struct stat sbuf; X struct timeval tv; X X sprintf(mail, "/usr/spool/mail/%s", getenv("USER")); X if (stat(mail, &sbuf) == -1) return 0; X X if (sbuf.st_size == 0) return 0; X X if (gettimeofday(&tv, NULL) == -1){ X fprintf(stderr, "Could not gettimeofday\n"); X exit(1); X } X X return tv.tv_sec - sbuf.st_mtime <= NEW_MAIL; X} X X is_manpage(sect, command) char *sect; char *command; X{ X /* Check to see if there is a man page for "command" in section "sect" */ X X char file[BIG]; X struct stat sbuf; X X /* Watch here, there could be sections like 3x or 3f etc etc. */ X if (strlen(sect) == 1 && index(MANSECTIONS, *sect) == NULL) return 0; X X sprintf(file, "/usr/man/man%s/%s.%s", sect, command, sect); X return stat(file, &sbuf) == 0; X} X X is_mailalias(s) char *s; X{ X /* Check ~/.mailrc to see if there is an alias by the name of "s" */ X X FILE *f; X char line[BIG]; X int slen = strlen(s); X X sprintf(line, "/u/%s/.mailrc", getenv("USER")); X if ((f = openfile(line, "r", 0)) == NULL) return 0; X X while (fgets(line, BIG, f) != NULL){ X register char *temp; X X if (strncmp(line, "alias", 5)) continue; X X temp = line + 5; X while (*temp == ' ' || *temp == '\t') temp++; X X if (strncmp(temp, s, slen) == 0) return 1; X } X return 0; X} X is_sysmailalias(s) char *s; X{ X /* Is "s" an alias in /usr/lib/aliases? */ X X FILE *f; X char line[BIG]; X int slen = strlen(s); X X if ((f = openfile("/usr/lib/aliases", "r", 0)) == NULL) return 0; X X while (fgets(line, BIG, f) != NULL){ X if (strncmp(line, s, slen) == 0 && line[slen] == ':') return 1; X } X return 0; X} X X is_maketarget(s) char *s; X{ X /* Is "s" a target in a makefile? */ X X FILE *f; X char line[BIG]; X int slen = strlen(s); X X if ((f = openfile("Makefile", "r", 0)) == NULL) X if ((f = openfile("makefile", "r", 0)) == NULL) X return 0; X X while (fgets(line, BIG, f) != NULL){ X if (strncmp(line, s, slen) == 0 && X (line[slen] == ':' || line[slen] == '\t' || line[slen] == ' ')) X X return 1; X } X return 0; X} X X X#define CLOBBER 1 X XFILE * openfile(s,mode,flag) char *s; char *mode; int flag; X{ X /* X * fopen() the file whose name is "s". X * If mode is write and clobber is 0, don't cloober an existing file. X * X * flag is clobber mode for "w". 1 = clobber existing file. X * X */ X X X FILE *fp, *fopen(); X struct stat buf; X X if (*mode=='w' && flag != CLOBBER && stat(s, &buf) != -1) return NULL; X if (!(fp=fopen(s,mode))) return NULL; X return fp; X} END_OF_FILE if test 8315 -ne `wc -c <'m/m.c'`; then echo shar: \"'m/m.c'\" unpacked with wrong size! fi # end of 'm/m.c' fi if test -f 'm/tags' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'m/tags'\" else echo shar: Extracting \"'m/tags'\" \(451 characters\) sed "s/^X//" >'m/tags' <<'END_OF_FILE' Mm m.c /^main(argc, argv)$/ go m.c /^go(s, args)$/ hascomma m.c /^hascomma(s1, s2)$/ is_mailalias m.c /^is_mailalias(s)$/ is_maketarget m.c /^is_maketarget(s)$/ is_manpage m.c /^is_manpage(sect, command)$/ is_minus m.c /^is_minus(flag, s)$/ is_ord_file m.c /^is_ord_file(s)$/ is_sysmailalias m.c /^is_sysmailalias(s)$/ is_userid m.c /^is_userid(s)$/ makefile m.c /^makefile()$/ openfile m.c /^openfile(s,mode,flag)$/ recent_mail m.c /^recent_mail()$/ END_OF_FILE if test 451 -ne `wc -c <'m/tags'`; then echo shar: \"'m/tags'\" unpacked with wrong size! fi # end of 'm/tags' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0