home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / xc < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  10.5 KB

  1. From decwrl!wyse!uunet!allbery Sun Jan 29 16:45:24 PST 1989
  2. Article 784 of comp.sources.misc:
  3. Path: granite!decwrl!wyse!uunet!allbery
  4. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Newsgroups: comp.sources.misc
  6. Subject: v06i009: xc: a mini-make
  7. Message-ID: <47273@uunet.UU.NET>
  8. Date: 24 Jan 89 02:59:25 GMT
  9. Sender: allbery@uunet.UU.NET
  10. Reply-To: edf@ROCKY2.ROCKEFELLER.EDU (David MacKenzie)
  11. Lines: 422
  12. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  13.  
  14. Posting-number: Volume 6, Issue 9
  15. Submitted-by: edf@ROCKY2.ROCKEFELLER.EDU (David MacKenzie)
  16. Archive-name: xc
  17.  
  18. Xc is a program to execute commands within source code files.
  19. It's mainly useful for compiling small programs where there are 
  20. many of them stored in one directory and keeping a lot of makefiles
  21. around would be a pain.  It doesn't do any timestamp-checking
  22. like make does, but it's not really meant for projects that are
  23. composed of multiple source files anyway.
  24.  
  25. A typical C program source file might start out like
  26.  
  27. /*
  28. % cc -O foo.c -o foo -ltermcap
  29. %i cc -O foo.c -o foo -ltermcap
  30. %i cp foo /usr/new; chmod 755 /usr/new/foo
  31. */
  32.  
  33. So you could ``xc foo.c'' to make it, or ``xc -i foo.c'' to make and
  34. install it.
  35.  
  36. Xc is distantly descended from an anonymous program of the same name
  37. that I found on a computer at St. Olaf College a couple of years ago.
  38. Not much remains of the original code, though.
  39.  
  40. -----
  41. David MacKenzie
  42. Environmental Defense Fund
  43. edf@rocky2.rockefeller.edu (...rutgers!cmcl2!rocky2!edf)
  44.  
  45. #! /bin/sh
  46. # This is a shell archive.  Remove anything before this line, then unpack
  47. # it by saving it into a file and typing "sh file".  To overwrite existing
  48. # files, type "sh file -c".  You can also feed this as standard input via
  49. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  50. # will see the following message at the end:
  51. #        "End of shell archive."
  52. # Contents:  xc.1 xc.c
  53. # Wrapped by dave@zedfdc  on Fri Dec 30 02:09:39 1988
  54. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  55. if test -f 'xc.1' -a "${1}" != "-c" ; then 
  56.   echo shar: Will not clobber existing file \"'xc.1'\"
  57. else
  58. echo shar: Extracting \"'xc.1'\" \(1327 characters\)
  59. sed "s/^X//" >'xc.1' <<'END_OF_FILE'
  60. X.TH XC 1L
  61. X.SH NAME
  62. Xxc, xcb \- execute commands contained in a file
  63. X.SH SYNOPSIS
  64. X.B xc
  65. Xor
  66. X.B xcb
  67. X[
  68. X.B \-c key_character
  69. X] [
  70. X.B file
  71. X]
  72. X.SH DESCRIPTION
  73. X.I Xc
  74. Xsearches a
  75. X.I file
  76. Xfor a sequence of lines with the form
  77. X.sp
  78. X%c command_line
  79. X.sp
  80. Xor
  81. X.sp
  82. X$c command_line
  83. X.sp
  84. Xwhere 'c' is a single key character given with the
  85. X.I \-c
  86. Xcommand line option.
  87. XIt then executes each
  88. X.I command_line
  89. Xin turn.
  90. X.PP
  91. XIf the
  92. X.I \-c
  93. Xoption is omitted, lines with the form
  94. X.sp
  95. X% command_line
  96. X.sp
  97. Xor
  98. X.sp
  99. X$ command_line
  100. X.sp
  101. Xare executed.  The `%' form echos the command line; the `$' form does not.
  102. X.PP
  103. XWhen invoked as
  104. X.I xcb,
  105. Xthe program automatically runs in the background, redirects the
  106. Xstandar output and standard error output to the file
  107. X.BR ./ERRS ,
  108. Xand makes a short announcement
  109. Xon its controlling terminal when it finishes.
  110. X.PP
  111. X.I Xc
  112. Xsaves the last filename and key character which were used
  113. Xinto the file
  114. X.BR $HOME/.xc ,
  115. Xand uses that file's contents as the defaults if the
  116. X.I file
  117. Xargument is omitted.
  118. X.PP
  119. XIf the
  120. X.I file
  121. Xcontains program source code, the
  122. X.I xc
  123. Xcommand lines should probably be enclosed within comments;
  124. Xhowever, the `%' and `$' must be the first characters on their lines,
  125. Xand be immediately followed by the key characters.
  126. X.SH FILES
  127. X$HOME/.xc
  128. X.PP
  129. XERRS
  130. X.SH "SEE ALSO"
  131. X.BR cc (1),
  132. X.BR sh (1)
  133. X.SH AUTHOR
  134. XDavid MacKenzie (mostly)
  135. END_OF_FILE
  136. if test 1327 -ne `wc -c <'xc.1'`; then
  137.     echo shar: \"'xc.1'\" unpacked with wrong size!
  138. fi
  139. # end of 'xc.1'
  140. fi
  141. if test -f 'xc.c' -a "${1}" != "-c" ; then 
  142.   echo shar: Will not clobber existing file \"'xc.c'\"
  143. else
  144. echo shar: Extracting \"'xc.c'\" \(6428 characters\)
  145. sed "s/^X//" >'xc.c' <<'END_OF_FILE'
  146. X/*
  147. X   xc - execute commands contained in a file
  148. X   xcb - same, but in the background
  149. X
  150. X   Usage: xc  [-c key_character] [file]
  151. X          xcb [-c key_character] [file]
  152. X
  153. X   xc -c x file    key: 'x'    file: "file"
  154. X   xc file    key: ' '    file: "file"
  155. X   xc -c x    key: 'x'    file: ~/.xc
  156. X   xc        key: ~/.xc    file: ~/.xc
  157. X
  158. X   Searches a file for a sequence of lines (probably in a comment)
  159. X   with the form
  160. X   %c command_line
  161. X   or
  162. X   $c command_line
  163. X   where 'c' (any single character) in "%c" or "$c" is the same as
  164. X   the key character given with the "-c" option on the command line,
  165. X   and executes the command_lines.
  166. X   If the "-c" option is omitted, lines with the form
  167. X   % command_line
  168. X   or
  169. X   $ command_line
  170. X   are executed.
  171. X   The '%' form echos the command_line; the '$' form does not.
  172. X
  173. X   When invoked as xcb, it automatically runs in the background, redirects
  174. X   stdout and stderr to the file ./ERRS, and announces when it finishes.
  175. X
  176. X   It saves the last filename and key character which were used
  177. X   into $HOME/.xc, and uses that file's contents as the defaults if the
  178. X   filename argument is omitted.
  179. X   $HOME/.xc contains one line of the form:
  180. X   c-filename
  181. X   where 'c' is the key character, or a space if none was given.
  182. X
  183. X   Latest modification: 12/30/88 */
  184. X
  185. X#include <stdio.h>
  186. X
  187. X#define XCFILE      "/.xc"    /* Where default file, key are read from. */
  188. X#define ERRFILE     "ERRS"    /* Where output goes if in background.  */
  189. X
  190. Xvoid perror (), exit ();
  191. Xchar *getenv (), *strcpy (), *strcat (), *strchr (), *strrchr (), *fgets ();
  192. X
  193. Xvoid pfatal (), usage ();
  194. Xvoid read_xc_file (), write_xc_file ();
  195. Xvoid detatch (), notify (), execute ();
  196. Xchar *make_xc_name (), *basename ();
  197. X
  198. Xchar *program_name;        /* Base of program name. */
  199. X
  200. Xmain (argc, argv)
  201. X  int argc;
  202. X  char **argv;
  203. X{
  204. X  extern int optind;        /* Option index. */
  205. X  extern char *optarg;        /* Option argument. */
  206. X  char *xcfile;            /* Expansion of "$HOME/.xc". */
  207. X  char *file_name;        /* File to get commands from. */
  208. X  char key;            /* Command line selector. */
  209. X  int background;        /* Run in the background? */
  210. X  int c;            /* Option character. */
  211. X
  212. X  program_name = basename (argv[0]);
  213. X  file_name = NULL;
  214. X  key = 0;
  215. X  background = !strcmp (program_name, "xcb");
  216. X  xcfile = make_xc_name ();
  217. X
  218. X  while ((c = getopt(argc, argv, "c:")) != EOF)
  219. X    switch (c)
  220. X      {
  221. X      case 'c':
  222. X    if (strlen (optarg) != 1)
  223. X      {
  224. X        fprintf (stderr, "%s: %s: Key must be one character long\n",
  225. X          argv[0], optarg);
  226. X        usage ();
  227. X      }
  228. X    key = *optarg;
  229. X    break;
  230. X      default:
  231. X    usage ();
  232. X      }
  233. X
  234. X  if (optind < argc - 1)
  235. X    usage ();
  236. X  else if (optind == argc - 1)
  237. X    file_name = argv[optind];
  238. X  else
  239. X    /* Read filename, and key if not set yet, from XCFILE. */
  240. X    read_xc_file (xcfile, &file_name, &key);
  241. X
  242. X  if (key == 0 || key == '\t')
  243. X    key = ' ';
  244. X
  245. X  if (background)
  246. X    detatch ();
  247. X
  248. X  execute (file_name, key);
  249. X
  250. X  write_xc_file (xcfile, file_name, key);
  251. X
  252. X  if (background)
  253. X    notify ();
  254. X
  255. X  exit (0);
  256. X}
  257. X
  258. X/* Return the path of the file "$HOME/.xc".  */
  259. X
  260. Xchar *make_xc_name ()
  261. X{
  262. X  static char xcbuf[BUFSIZ];    /* "$HOME/XCFILE". */
  263. X  char *home;
  264. X
  265. X  home = getenv ("HOME");
  266. X  if (!home)
  267. X    {
  268. X      fprintf (stderr,
  269. X    "%s: HOME environment variable is not defined\n", program_name);
  270. X      exit (1);
  271. X    }
  272. X  (void) strcpy (xcbuf, home);
  273. X  (void) strcat (xcbuf, XCFILE);
  274. X  return xcbuf;
  275. X}
  276. X
  277. X/* Read from xcfile the filename, and the key if it's not already set.  */
  278. X
  279. Xvoid read_xc_file (xcfile, file_namep, keyp)
  280. X  char *xcfile;
  281. X  char **file_namep;
  282. X  char *keyp;
  283. X{
  284. X  FILE *fp;
  285. X  char *newline;
  286. X  static char line[BUFSIZ];
  287. X
  288. X  fp = fopen (xcfile, "r");
  289. X  if (!fp)
  290. X    pfatal (xcfile);
  291. X  (void) fgets (line, BUFSIZ, fp);
  292. X  newline = strchr (line, '\n');
  293. X  if (newline)
  294. X    *newline = 0;
  295. X  (void) fclose (fp);
  296. X
  297. X  *file_namep = &line[2];
  298. X  if (*keyp == 0)
  299. X    *keyp = *line;
  300. X}
  301. X
  302. X/* Update the xcfile.  */
  303. X
  304. Xvoid write_xc_file (xcfile, file_name, key)
  305. X  char *xcfile;
  306. X  char *file_name;
  307. X  char key;
  308. X{
  309. X  FILE *fp;
  310. X
  311. X  fp = fopen (xcfile, "w");
  312. X  if (!fp)
  313. X    return;
  314. X  fprintf (fp, "%c-%s\n", key, file_name);
  315. X  (void) fclose (fp);
  316. X}
  317. X
  318. Xstatic int save_stdout;        /* Save file descriptor for notification. */
  319. X
  320. X/* Redirect the standard streams and fade into the background.  */
  321. X
  322. Xvoid detatch ()
  323. X{
  324. X  save_stdout = dup (1);
  325. X  if (save_stdout == -1)
  326. X    pfatal ("Can't dup standard output");
  327. X  if (!freopen (ERRFILE, "w", stdout))
  328. X    pfatal (ERRFILE);
  329. X  (void) close (2);
  330. X  if (dup (1) != 2)        /* Could be 0 if stdin was closed. */
  331. X    if (dup (1) == -1)
  332. X      pfatal ("Can't dup standard output");
  333. X  switch (fork ())
  334. X    {
  335. X    case -1:
  336. X      pfatal ("Can't fork");
  337. X    case 0:
  338. X      break;
  339. X    default:
  340. X      exit (0);
  341. X    }
  342. X}
  343. X
  344. Xvoid notify ()
  345. X{
  346. X  (void) write (save_stdout, "\r\n\007[xcb: done]\r\n", 16);
  347. X  printf ("Done\n");
  348. X  (void) fflush (stdout);
  349. X}
  350. X
  351. X/* Read the file and execute command lines that match the key.  */
  352. X
  353. Xvoid execute (file_name, key)
  354. X  char *file_name;
  355. X  char key;
  356. X{
  357. X  FILE *fp;            /* Pointer to file stream. */
  358. X  char line[BUFSIZ];        /* One line of file. */
  359. X  char *command;        /* Command to execute. */
  360. X  int key_matched = 0;        /* Has command line matching key been found? */
  361. X  int status;            /* Return status from system. */
  362. X
  363. X  fp = fopen (file_name, "r");
  364. X  if (!fp)
  365. X    pfatal (file_name);
  366. X
  367. X  while (fgets (line, BUFSIZ, fp))
  368. X    {
  369. X      if (line[1] == '\t')
  370. X    line[1] = ' ';
  371. X      if ((*line != '%' && *line != '$') || line[1] != key)
  372. X    {
  373. X      if (key_matched)
  374. X        break;
  375. X      else
  376. X        continue;
  377. X    }
  378. X      key_matched = 1;
  379. X      /* Skip leading whitespace in the command for aesthetic reasons. */
  380. X      for (command = &line[2];
  381. X    *command && (*command == ' ' || *command == '\t'); ++command)
  382. X     /* Do nothing. */ ;
  383. X      if (*line == '%')
  384. X    {
  385. X      printf ("  %s", command);
  386. X      (void) fflush (stdout);
  387. X    }
  388. X      status = system (command);
  389. X      if (status)
  390. X    {
  391. X      fprintf (stderr, "%s: ** Exit status 0%o **\n", program_name, status);
  392. X      break;
  393. X    }
  394. X    }
  395. X  (void) fclose (fp);
  396. X
  397. X  if (!key_matched)
  398. X    {
  399. X      fprintf (stderr,
  400. X    "%s: %s: No commands for key '%c'\n", program_name, file_name, key);
  401. X      exit (1);
  402. X    }
  403. X}
  404. X
  405. X/* Return name with any leading path stripped off.  */
  406. X
  407. Xchar *basename (name)
  408. X  char *name;
  409. X{
  410. X  char *base;
  411. X
  412. X  base = strrchr (name, '/');
  413. X  return base ? base + 1 : name;
  414. X}
  415. X
  416. Xvoid pfatal (message)
  417. X  char *message;
  418. X{
  419. X  fprintf (stderr, "%s: ", program_name);
  420. X  perror (message);
  421. X  exit (1);
  422. X}
  423. X
  424. Xvoid usage ()
  425. X{
  426. X  fprintf (stderr, "Usage: %s [-c key_character] [file]\n", program_name);
  427. X  exit (1);
  428. X}
  429. END_OF_FILE
  430. if test 6428 -ne `wc -c <'xc.c'`; then
  431.     echo shar: \"'xc.c'\" unpacked with wrong size!
  432. fi
  433. # end of 'xc.c'
  434. fi
  435. echo shar: End of shell archive.
  436.  
  437.  
  438.