home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / xc < prev    next >
Internet Message Format  |  1989-02-03  |  11KB

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