home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / m < prev    next >
Encoding:
Text File  |  1991-08-27  |  15.7 KB  |  553 lines

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