home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / m < prev    next >
Text File  |  1989-03-21  |  16KB  |  549 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v06i071: m - the more/mail/make/man thing
  4. Reply-To: tcjones@watdragon.waterloo.edu (speedboat jones)
  5. Distribution: world
  6. Organization: U. of Waterloo, Ontario
  7.  
  8. Posting-number: Volume 6, Issue 71
  9. Submitted-by: tcjones@watdragon.waterloo.edu (speedboat jones)
  10. Archive-name: m
  11.  
  12. [It's easier to shoot such people on sight -- or "unalias m" as your first
  13. action.  I don't use alias abbreviations, since their interpretation is
  14. always open to question and I have to deal with some 30 systems on a day-
  15. to-day basis, sharing an alias file with at least two other people.  ++bsa]
  16.  
  17. Here is an extremely silly thing called "m". Isn't frustrating how some
  18. people alias m for mail, others use m for more, and some even use it
  19. for man? So that when you type at their terminal when they have their
  20. backs turned you can never get anything right?
  21.  
  22. M is a more/mail/make/man thing. You just use m instead of any of those
  23. four and it attempts to figure out what you meant and execute the
  24. appropriate thing for you. It usually gets it right and if not, well,
  25. you can't be hurt too much.  And you can always use the real command.
  26.  
  27. This, of course, does not solve the above problem, so I suggest that 
  28. everyone who uses this program changes their prompt to
  29.     I-Use-M:
  30. so that the rest of the world will know.
  31.  
  32. Whatever. Have fun etc. This will need a few changes to work on non-BSD
  33. systems I think.
  34.  
  35.  
  36. Here is (sort of) what happens...
  37.  
  38. You type:             m thinks:
  39. ---------------------------------------------
  40. unix_command | m      more
  41.  
  42. m                     mail (if there is recent mail)... ELSE
  43.                       make (if there is a Makefile or makefile)... ELSE
  44.                       mail
  45.  
  46. m X                   more X (if X is an ordinary file.) ELSE...
  47.                       mail X (if X is a user name or mail alias). ELSE...
  48.                       make X (if X is a makefile target).
  49.                       man X.
  50.  
  51. m A, B...             mail A, B...
  52. m x X                 man x X (if x is a manual section and X a manpage)
  53. m -f                  mail -f
  54. m -f X                mail -f X (if X is an ordinary file).
  55. m -k X                man -k X
  56.  
  57.  
  58.  
  59.  
  60. Terry Jones
  61.  
  62.     Department Of Computer Science,  University Of Waterloo
  63.     Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
  64.     UUCP:                    ...!watmath!watdragon!tcjones
  65.     CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
  66.     BITNET:                  tcjones@WATER.bitnet
  67.     Canadian domain:         tcjones@dragon.uwaterloo.ca
  68.  
  69. #! /bin/sh
  70. # This is a shell archive.  Remove anything before this line, then unpack
  71. # it by saving it into a file and typing "sh file".  To overwrite existing
  72. # files, type "sh file -c".  You can also feed this as standard input via
  73. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  74. # will see the following message at the end:
  75. #        "End of archive 1 (of 1)."
  76. # Contents:  m m/Makefile m/README m/m.c m/tags
  77. # Wrapped by tcjones@watdragon on Wed Mar 15 13:01:48 1989
  78. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  79. if test ! -d 'm' ; then
  80.     echo shar: Creating directory \"'m'\"
  81.     mkdir 'm'
  82. fi
  83. if test -f 'm/Makefile' -a "${1}" != "-c" ; then 
  84.   echo shar: Will not clobber existing file \"'m/Makefile'\"
  85. else
  86. echo shar: Extracting \"'m/Makefile'\" \(43 characters\)
  87. sed "s/^X//" >'m/Makefile' <<'END_OF_FILE'
  88. CFLAGS = -O
  89. X
  90. m: m.o
  91. X    cc $(CFLAGS) -o m m.o
  92. END_OF_FILE
  93. if test 43 -ne `wc -c <'m/Makefile'`; then
  94.     echo shar: \"'m/Makefile'\" unpacked with wrong size!
  95. fi
  96. # end of 'm/Makefile'
  97. fi
  98. if test -f 'm/README' -a "${1}" != "-c" ; then 
  99.   echo shar: Will not clobber existing file \"'m/README'\"
  100. else
  101. echo shar: Extracting \"'m/README'\" \(1835 characters\)
  102. sed "s/^X//" >'m/README' <<'END_OF_FILE'
  103. X
  104. Here is an extremely silly thing called "m". Isn't frustrating how some people
  105. alias m for mail, others use m for more, and some even use it for man? So that
  106. when you type at their terminal when they have their backs turned you can never
  107. get anything right? 
  108. X
  109. M is a more/mail/make/man thing. You just use m instead of any of those four
  110. and it attempts to figure out what you meant and execute the appropriate thing
  111. for you. It usually gets it right and if not, well, you can't be hurt too much.
  112. And you can always use the real command.
  113. X
  114. This, of course, does not solve the above problem, so I suggest that everyone
  115. who uses this program changes their prompt to
  116. I-Use-M:
  117. so that the rest of the world will know :-)
  118. X
  119. Whatever. Have fun etc.
  120. X
  121. X
  122. Here is (sort of) what happens...
  123. X
  124. You type:             m thinks:
  125. X---------------------------------------------
  126. unix_command | m      more
  127. X
  128. m                     mail (if there is recent mail)... ELSE
  129. X                      make (if there is a Makefile or makefile)... ELSE
  130. X                      mail
  131. X
  132. m X                   more X (if X is an ordinary file.) ELSE...
  133. X                      mail X (if X is a user name or mail alias). ELSE...
  134. X                      make X (if X is a makefile target).
  135. X                      man X.
  136. X
  137. m A, B...             mail A, B...
  138. m x X                 man x X (if x is a manual section and X a manpage)
  139. m -f                  mail -f
  140. m -f X                mail -f X (if X is an ordinary file).
  141. m -k X                man -k X
  142. X
  143. X
  144. X
  145. X
  146. Terry Jones
  147. X
  148. X    Department Of Computer Science,  University Of Waterloo
  149. X    Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
  150. X    UUCP:                    ...!watmath!watdragon!tcjones
  151. X    CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
  152. X    BITNET:                  tcjones@WATER.bitnet
  153. X    Canadian domain:         tcjones@dragon.uwaterloo.ca
  154. END_OF_FILE
  155. if test 1835 -ne `wc -c <'m/README'`; then
  156.     echo shar: \"'m/README'\" unpacked with wrong size!
  157. fi
  158. # end of 'm/README'
  159. fi
  160. if test -f 'm/m.c' -a "${1}" != "-c" ; then 
  161.   echo shar: Will not clobber existing file \"'m/m.c'\"
  162. else
  163. echo shar: Extracting \"'m/m.c'\" \(8315 characters\)
  164. sed "s/^X//" >'m/m.c' <<'END_OF_FILE'
  165. X/*
  166. X * m.c  --  man/mail/make/more guesswork.
  167. X *
  168. X * Invoke one of the above four by looking at our arguments and deciding
  169. X * which is the appropriate one. Has limitations but is fun...
  170. X *
  171. X * Terry Jones
  172. X *
  173. X * -----------------------------------------------------------------------------
  174. X * Department Of Computer Science, University Of Waterloo
  175. X * Waterloo Ontario Canada N2L 3G1
  176. X *
  177. X * {ihnp4,allegra,decvax,utzoo,utcsri,clyde}!watmath!watdragon!tcjones
  178. X * tcjones@dragon.waterloo.{cdn,edu} tcjones@WATER.bitnet
  179. X * tcjones%watdragon@waterloo.csnet 
  180. X * -----------------------------------------------------------------------------
  181. X */
  182. X
  183. X#include <stdio.h>
  184. X#include <sys/types.h>
  185. X#include <sys/stat.h>
  186. X#include <sys/time.h>
  187. X
  188. X/* Some laziness to make things clearer(?) down below */
  189. X
  190. X#define MORE go(more, ARGS)
  191. X#define MAN  go("man", ARGS)
  192. X#define MAIL go("mail", ARGS)
  193. X#define MAKE go("make", ARGS)
  194. X
  195. X#define BIG 4096
  196. X
  197. X/* More laziness. ARGn means "original argument n"
  198. X *                RARGn means "real (non-option) argument n"
  199. X *
  200. X *  Options are assumed to come first on the command line and to start with '-'
  201. X *
  202. X */
  203. X
  204. X#define ARGS orig_argv
  205. X#define ARG0 (*orig_argv)
  206. X#define ARG1 (*(orig_argv+1))
  207. X#define RARG0 (*argv)
  208. X#define RARG1 (*(argv+1))
  209. X
  210. X/* Sections of the manual that we can recognize. */
  211. X#define MANSECTIONS "0123456789cinopt"
  212. X
  213. X/* Mail is "new" if less than this number of seconds old. */
  214. X#define NEW_MAIL 120
  215. X
  216. extern char *getenv();
  217. extern char *index();
  218. extern FILE *openfile();
  219. X
  220. char *myname;
  221. char *more;
  222. X
  223. main(argc, argv)
  224. int argc;
  225. char **argv;
  226. X{
  227. X    /* Save the original argument list and count. */
  228. X    register char **orig_argv = argv;
  229. X    register int orig_argc = argc;
  230. X
  231. X    myname = *argv;
  232. X
  233. X    argc--;
  234. X    argv++;
  235. X
  236. X    /* Skip option arguments. */
  237. X    while (**argv == '-'){
  238. X        argv++;
  239. X        argc--;
  240. X    }
  241. X
  242. X    if (!(more = getenv("PAGER"))) more = "more";
  243. X
  244. X    /* 
  245. X     * argc now hold the number of non-option arguments, argv points
  246. X     * to the first non-option argument.
  247. X     *
  248. X     * The order in which we do the following tests will make an efficiency
  249. X     * difference - try to do more likely and faster tests first.
  250. X     *
  251. X     */
  252. X
  253. X    if (argc == 0 && isatty(0) == 0)                                    MORE;
  254. X    if (argc == 0 && recent_mail())                                     MAIL;
  255. X    if (argc == 0 && makefile())                                        MAKE;
  256. X    if (argc == 1 && is_ord_file(RARG0))                                MORE;
  257. X    if (argc > 0 && hascomma(RARG0, RARG1))                             MAIL;
  258. X    if (argc == 0)                                                      MAIL;
  259. X    if (argc == 1 && is_userid(RARG0))                                  MAIL;
  260. X    if (argc == 1 && is_mailalias(RARG0))                               MAIL;
  261. X    if (argc == 2 && is_manpage(RARG0, RARG1))                          MAN;
  262. X    if (orig_argc == 2 && is_minus('f', ARG1))                          MAIL;
  263. X    if (orig_argc == 3 && is_minus('f', ARG1) && is_ord_file(RARG0))    MAIL;
  264. X    if (argc == 1 && is_maketarget(RARG0))                              MAKE;
  265. X    if (orig_argc == 3 && is_minus('k', ARG1))                          MAN;
  266. X    if (argc == 1 && is_sysmailalias(RARG0))                            MAIL;
  267. X    if (argc == 1)                                                      MAN;
  268. X    
  269. X
  270. X    /* Give up. */
  271. X    printf("%s: Couldn't decide what to do!\n", myname);
  272. X    exit(1);
  273. X}
  274. X
  275. go(s, args)
  276. char *s;
  277. char **args;
  278. X{
  279. X    /* Exec the command passed in using s, with all the original arguments. */
  280. X
  281. X    register char **tmp;
  282. X    *args = s;
  283. X    /*
  284. X     * We could print the new command but it doesn't seem necessary -
  285. X     * the result should make it obvious what we have done.
  286. X     *
  287. X     *   tmp = args;
  288. X     *   while(**tmp) printf("%s ", *tmp++);
  289. X     *   putc('\n', stdout);
  290. X     */
  291. X
  292. X    execvp(s, args);
  293. X    printf(stderr, "%s: Could not execvp %s\n", myname, s);
  294. X    exit(1);
  295. X}
  296. X
  297. X
  298. is_ord_file(s)
  299. char *s;
  300. X{
  301. X    /* Check to see if "s" is an ordinary file. */
  302. X    /* i.e. not a directory etc. */
  303. X    /* if it is executable and also a maketarget then return 0 & it gets made */
  304. X
  305. X    struct stat sbuf;
  306. X
  307. X    if (stat(s, &sbuf) == -1) return 0;
  308. X    if (sbuf.st_mode & S_IFMT != S_IFREG) return 0;
  309. X    if ((sbuf.st_mode & S_IEXEC) && is_maketarget(s)) return 0;
  310. X    return 1;
  311. X}
  312. X
  313. hascomma(s1, s2)
  314. char *s1;
  315. char *s2;
  316. X{
  317. X    /* 
  318. X     * Check to see if either s1 or s2 has a comma. This would seem to
  319. X     * imply that the arguments are a comma separated list for mail.
  320. X     *
  321. X     */
  322. X
  323. X    return index(s1, ',') != NULL || index(s2, ',') != NULL;
  324. X}
  325. X
  326. makefile()
  327. X{
  328. X    /* Check to see if there is a makefile of some description. */
  329. X
  330. X    struct stat sbuf;
  331. X    return stat("Makefile", &sbuf) == 0 || stat("makefile", &sbuf) == 0;
  332. X}
  333. X
  334. is_minus(flag, s)
  335. char flag;
  336. char *s;
  337. X{
  338. X    /* 
  339. X     * Check if "s" is the option given by the flag "flag".
  340. X     * This could be a #define, and so could lots of the next few things.
  341. X     *
  342. X     * But they're ugly.
  343. X     *
  344. X     */
  345. X
  346. X    return s[0] == '-' && s[1] == flag && s[2] =='\0';
  347. X}
  348. X
  349. X
  350. is_userid(s)
  351. char *s;
  352. X{
  353. X    /* 
  354. X     * Is "s" a userid? 
  355. X     * Look for a '@' or a '!' for a remote person, or
  356. X     * check /u/"s" to find out locally.
  357. X     *
  358. X     */
  359. X
  360. X    struct passwd *getpwnam();
  361. X
  362. X    if (index(s, '!') || index(s, '@')) return 1;
  363. X    return getpwnam(s) != NULL;
  364. X}
  365. X
  366. recent_mail()
  367. X{
  368. X    /* 
  369. X     * See if there is mail which has arrived in the last NEW_MAIL seconds.
  370. X     * This could be much better. It could include a check to see if the
  371. X     * mailbox was touched before you logged on and after your previous
  372. X     * logoff - but who wants to read backwards through /usr/adm/wtmp ??
  373. X     *
  374. X     */
  375. X
  376. X    char mail[BIG];
  377. X    struct stat sbuf;
  378. X    struct timeval tv;
  379. X
  380. X    sprintf(mail, "/usr/spool/mail/%s", getenv("USER"));
  381. X    if (stat(mail, &sbuf) == -1) return 0;
  382. X
  383. X    if (sbuf.st_size == 0) return 0;
  384. X
  385. X    if (gettimeofday(&tv, NULL) == -1){
  386. X        fprintf(stderr, "Could not gettimeofday\n");
  387. X        exit(1);
  388. X    }
  389. X
  390. X    return tv.tv_sec - sbuf.st_mtime <= NEW_MAIL;
  391. X}
  392. X
  393. X
  394. is_manpage(sect, command)
  395. char *sect;
  396. char *command;
  397. X{
  398. X    /* Check to see if there is a man page for "command" in section "sect"  */
  399. X
  400. X    char file[BIG];
  401. X    struct stat sbuf;
  402. X
  403. X    /* Watch here, there could be sections like 3x or 3f etc etc. */
  404. X    if (strlen(sect) == 1 && index(MANSECTIONS, *sect) == NULL) return 0;
  405. X
  406. X    sprintf(file, "/usr/man/man%s/%s.%s", sect, command, sect);
  407. X    return stat(file, &sbuf) == 0;
  408. X}
  409. X
  410. X
  411. is_mailalias(s)
  412. char *s;
  413. X{
  414. X    /* Check ~/.mailrc to see if there is an alias by the name of "s" */
  415. X
  416. X    FILE *f;
  417. X    char line[BIG];
  418. X    int slen = strlen(s);
  419. X
  420. X    sprintf(line, "/u/%s/.mailrc", getenv("USER"));
  421. X    if ((f = openfile(line, "r", 0)) == NULL) return 0;
  422. X
  423. X    while (fgets(line, BIG, f) != NULL){
  424. X        register char *temp;
  425. X
  426. X        if (strncmp(line, "alias", 5)) continue;
  427. X
  428. X        temp = line + 5;
  429. X        while (*temp == ' ' || *temp == '\t') temp++;
  430. X
  431. X        if (strncmp(temp, s, slen) == 0) return 1;
  432. X    }
  433. X    return 0;
  434. X}
  435. X
  436. is_sysmailalias(s)
  437. char *s;
  438. X{
  439. X    /* Is "s" an alias in /usr/lib/aliases? */
  440. X
  441. X    FILE *f;
  442. X    char line[BIG];
  443. X    int slen = strlen(s);
  444. X
  445. X    if ((f = openfile("/usr/lib/aliases", "r", 0)) == NULL) return 0;
  446. X
  447. X    while (fgets(line, BIG, f) != NULL){
  448. X        if (strncmp(line, s, slen) == 0 && line[slen] == ':') return 1;
  449. X    }
  450. X    return 0;
  451. X}
  452. X
  453. X
  454. is_maketarget(s)
  455. char *s;
  456. X{
  457. X    /* Is "s" a target in a makefile? */
  458. X
  459. X    FILE *f;
  460. X    char line[BIG];
  461. X    int slen = strlen(s);
  462. X
  463. X    if ((f = openfile("Makefile", "r", 0)) == NULL)
  464. X        if ((f = openfile("makefile", "r", 0)) == NULL)
  465. X            return 0;
  466. X
  467. X    while (fgets(line, BIG, f) != NULL){
  468. X        if (strncmp(line, s, slen) == 0 && 
  469. X            (line[slen] == ':' || line[slen] == '\t' || line[slen] == ' '))
  470. X
  471. X            return 1;
  472. X    }
  473. X    return 0;
  474. X}
  475. X
  476. X
  477. X#define CLOBBER 1
  478. X
  479. XFILE *
  480. openfile(s,mode,flag)
  481. char *s;
  482. char *mode;
  483. int flag;
  484. X{
  485. X    /* 
  486. X     * fopen() the file whose name is "s".
  487. X     * If mode is write and clobber is 0, don't cloober an existing file.
  488. X     *
  489. X     * flag is clobber mode for "w". 1 = clobber existing file.
  490. X     *
  491. X     */
  492. X
  493. X
  494. X    FILE *fp, *fopen();
  495. X    struct stat buf;
  496. X
  497. X    if (*mode=='w' && flag != CLOBBER && stat(s, &buf) != -1) return NULL;
  498. X    if (!(fp=fopen(s,mode))) return NULL;
  499. X    return fp;
  500. X}
  501. END_OF_FILE
  502. if test 8315 -ne `wc -c <'m/m.c'`; then
  503.     echo shar: \"'m/m.c'\" unpacked with wrong size!
  504. fi
  505. # end of 'm/m.c'
  506. fi
  507. if test -f 'm/tags' -a "${1}" != "-c" ; then 
  508.   echo shar: Will not clobber existing file \"'m/tags'\"
  509. else
  510. echo shar: Extracting \"'m/tags'\" \(451 characters\)
  511. sed "s/^X//" >'m/tags' <<'END_OF_FILE'
  512. Mm    m.c    /^main(argc, argv)$/
  513. go    m.c    /^go(s, args)$/
  514. hascomma    m.c    /^hascomma(s1, s2)$/
  515. is_mailalias    m.c    /^is_mailalias(s)$/
  516. is_maketarget    m.c    /^is_maketarget(s)$/
  517. is_manpage    m.c    /^is_manpage(sect, command)$/
  518. is_minus    m.c    /^is_minus(flag, s)$/
  519. is_ord_file    m.c    /^is_ord_file(s)$/
  520. is_sysmailalias    m.c    /^is_sysmailalias(s)$/
  521. is_userid    m.c    /^is_userid(s)$/
  522. makefile    m.c    /^makefile()$/
  523. openfile    m.c    /^openfile(s,mode,flag)$/
  524. recent_mail    m.c    /^recent_mail()$/
  525. END_OF_FILE
  526. if test 451 -ne `wc -c <'m/tags'`; then
  527.     echo shar: \"'m/tags'\" unpacked with wrong size!
  528. fi
  529. # end of 'm/tags'
  530. fi
  531. echo shar: End of archive 1 \(of 1\).
  532. cp /dev/null ark1isdone
  533. MISSING=""
  534. for I in 1 ; do
  535.     if test ! -f ark${I}isdone ; then
  536.     MISSING="${MISSING} ${I}"
  537.     fi
  538. done
  539. if test "${MISSING}" = "" ; then
  540.     echo You have the archive.
  541.     rm -f ark[1-9]isdone
  542. else
  543.     echo You still need to unpack the following archives:
  544.     echo "        " ${MISSING}
  545. fi
  546. ##  End of shell archive.
  547. exit 0
  548.  
  549.