PageRenderTime 78ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/1998/mkentry.c

https://bitbucket.org/c00kiemon5ter/ioccc-obfuscated-c-contest
C | 1280 lines | 681 code | 118 blank | 481 comment | 165 complexity | b3c01cc9940438c72f783308de5f21bb MD5 | raw file
  1. /* $Id: mkentry.c,v 1.6 1999/01/27 23:19:37 chongo Exp $ */
  2. /*
  3. * Copyright (c) Leonid A. Broukhis, Jeremy Horn, Landon Curt Noll and
  4. * Peter Seebach, 1998.
  5. *
  6. * All Rights Reserved. Permission for personal, education or non-profit use
  7. * is granted provided this this copyright and notice are included in its
  8. * entirety and remains unaltered. All other uses must receive prior
  9. * permission in writing from the contest judges.
  10. */
  11. /*
  12. * mkentry - make an International Obfuscated C Code Contest entry
  13. *
  14. * usage:
  15. * mkentry -r remarks -b build -p prog.c -o ioccc.entry
  16. *
  17. * -r remarks file with remarks about the entry
  18. * -b build file containing how prog.c should be built
  19. * -p prog.c the obfuscated program source file
  20. * -o ioccc.entry ioccc entry output file
  21. *
  22. * compile by:
  23. * cc mkentry.c -o mkentry
  24. */
  25. /*
  26. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  27. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  28. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  29. */
  30. /*
  31. * WARNING:
  32. *
  33. * This program attempts to implement the IOCCC rules. Every attempt
  34. * has been made to make sure that this program produces an entry that
  35. * conforms to the contest rules. In all cases, where this program
  36. * differs from the contest rules, the contest rules will be used. Be
  37. * sure to check with the contest rules before submitting an entry.
  38. *
  39. * FOR MORE INFORMATION:
  40. *
  41. * You may contact the judges by sending EMail to the following address:
  42. *
  43. * questions@ioccc.org (not the address for submitting entries)
  44. *
  45. * Questions and comments about the contest are welcome.
  46. *
  47. * You must include the words ``ioccc question'' in the subject of your
  48. * EMail message when sending EMail to the judges.
  49. *
  50. * Entries must be sent to:
  51. *
  52. * entry@ioccc.org
  53. *
  54. * but be sure to follow the rules and read the guidelines first!
  55. *
  56. * You must include the words ``ioccc entry'' in the subject
  57. * of your EMail when sending in your entry! Failure to do so may
  58. * result in the loss of your entry!
  59. *
  60. * The rules and the guidelines may (and often do) change from year to
  61. * year. You should be sure you have the current rules and guidelines
  62. * prior to submitting entries. To obtain them, visit the following URL:
  63. *
  64. * http://www.ioccc.org
  65. *
  66. * Because contest rules change from year to year, one should only use this
  67. * program for the year that it was intended.
  68. */
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include <ctype.h>
  73. #include <time.h>
  74. #include <sys/types.h>
  75. #include <sys/stat.h>
  76. /* logic */
  77. #ifndef TRUE
  78. # define TRUE 1
  79. #endif /* TRUE */
  80. #ifndef FALSE
  81. # define FALSE 0
  82. #endif /* FALSE */
  83. #define EOF_OK TRUE
  84. #define EOF_NOT_OK FALSE
  85. /* global limits */
  86. #define RULE_YEAR 1998 /* NOTE: should match the current year */
  87. #define START_DATE "26Nov98 12:00 UTC" /* first confirmation received */
  88. #define MAX_COL 79 /* max column a line should hit */
  89. #define MAX_BUILD_SIZE 256 /* max how to build size */
  90. #define MAX_PROGRAM_SIZE 3217 /* max program source size */
  91. #define MAX_PROGRAM_SIZE2 1536 /* max program source size not counting
  92. whitespace and {}; not followed by
  93. whitespace or EOF */
  94. #define MAX_TITLE_LEN 31 /* max chars in the title */
  95. #define MAX_ENTRY_LEN 1 /* max length in the entry input line */
  96. #define MAX_ENTRY 8 /* max number of entries per person per year */
  97. #define MAX_FILE_LEN 1024 /* max filename length for a info file */
  98. /* where to send entries */
  99. #define ENTRY_ADDR "entry@ioccc.org"
  100. /* uuencode process - assumes ASCII */
  101. #define UUENCODE(c) ((c) ? encode_str[(int)(c)&0x3f] : '`')
  102. #define UUENCODE_LEN 45 /* max uuencode chunk size */
  103. #define UUINFO_MODE 0444 /* mode of an info file's uuencode file */
  104. #define UUBUILD_MODE 0444 /* mode of the build file's uuencode file */
  105. #define UUBUILD_NAME "build" /* name for the build file's uuencode file */
  106. #define UUPROG_MODE 0444 /* mode of the program's uuencode file */
  107. #define UUPROG_NAME "prog.c" /* name for the program's uuencode file */
  108. /* encode_str[(char)val] is the uuencoded character of val */
  109. char encode_str[] = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
  110. /* global declarations */
  111. char *program; /* our name */
  112. long start_time; /* the startup time */
  113. /* forward declarations */
  114. void parse_args(int argc, char **argv, char **rname,
  115. char **bname, char **pname, char **oname);
  116. void usage(int exitval);
  117. FILE *open_remark(char *filename);
  118. FILE *open_build(char *filename);
  119. FILE *open_program(char *filename);
  120. FILE *open_output(char *filename);
  121. void output_entry(FILE *output, char *oname);
  122. void output_remark(FILE *output, char *oname, FILE *remark, char *rname);
  123. void output_author(FILE *output, char *oname);
  124. void output_info(FILE *output, char *oname);
  125. void output_build(FILE *output, char *oname, FILE *build, char *bname);
  126. void output_program(FILE *output, char *oname, FILE *prog, char *pname);
  127. void output_end(FILE *output, char *oname);
  128. int get_line(char *buf, int siz, int maxcol);
  129. void output_till_dot(FILE *output, char *oname, char *leader);
  130. int col_len(char *string);
  131. void check_io(FILE *stream, char *name, int eof_ok);
  132. void uuencode(FILE *output, char *oname, FILE *infile,
  133. char *iname, int umode, char *uname);
  134. int
  135. main(argc, argv)
  136. int argc; /* arg count */
  137. char **argv; /* the args */
  138. {
  139. FILE *remark=NULL; /* open remarks stream */
  140. FILE *build=NULL; /* open build file stream */
  141. FILE *prog=NULL; /* open program stream */
  142. FILE *output=NULL; /* open output stream */
  143. char *rname=NULL; /* file with remarks about the entry */
  144. char *bname=NULL; /* file containing how prog.c should be built */
  145. char *pname=NULL; /* the obfuscated program source file */
  146. char *oname=NULL; /* ioccc entry output file */
  147. struct tm *tm; /* startup time structure */
  148. /*
  149. * check on the year
  150. */
  151. start_time = time((long *)0);
  152. tm = gmtime(&start_time);
  153. if (tm->tm_year != RULE_YEAR-1900 &&
  154. (tm->tm_year != RULE_YEAR-1900+1 || tm->tm_mon != 0)) {
  155. fprintf(stderr,
  156. "%s: WARNING: this program applies to %d, which may differ from %d\n\n",
  157. argv[0], RULE_YEAR, 1900+tm->tm_year);
  158. }
  159. /*
  160. * parse the command line args
  161. */
  162. parse_args(argc, argv, &rname, &bname, &pname, &oname);
  163. /*
  164. * open/check the input and output files
  165. *
  166. * We open and truncate the output file first, in case it is the same
  167. * as one of the input files.
  168. */
  169. output = open_output(oname);
  170. remark = open_remark(rname);
  171. build = open_build(bname);
  172. prog = open_program(pname);
  173. if (output==NULL || remark==NULL || build==NULL || prog==NULL) {
  174. exit(1);
  175. }
  176. /*
  177. * output each section
  178. */
  179. output_entry(output, oname);
  180. output_remark(output, oname, remark, rname);
  181. output_author(output, oname);
  182. output_info(output, oname);
  183. output_build(output, oname, build, bname);
  184. output_program(output, oname, prog, pname);
  185. output_end(output, oname);
  186. /*
  187. * flush the output
  188. */
  189. if (fflush(output) == EOF) {
  190. fprintf(stderr, "%s: flush error in %s: ", program, oname);
  191. perror("");
  192. exit(2);
  193. }
  194. /*
  195. * final words
  196. */
  197. printf("\nYour entry can be found in %s. You should check this file\n",
  198. oname);
  199. printf("correct any problems and verify that the uudecode utility will\n");
  200. printf("correctly decode your build file and program.\n\n");
  201. printf("This program has been provided as a guide for submitters. In\n");
  202. printf("cases where it conflicts with the rules, the rules shall apply.\n");
  203. printf("It is your responsibility to ensure that your entry conforms to\n");
  204. printf("the current rules.\n\n");
  205. printf("EMail your entries to:\n");
  206. printf("\t%s\n\n", ENTRY_ADDR);
  207. printf("Please use the following subject when you EMail your entry:\n");
  208. printf("\tioccc entry\n\n");
  209. /* all done */
  210. return 0;
  211. }
  212. /*
  213. * parse_args - parse the command line args
  214. *
  215. * usage:
  216. * argc arg count
  217. * argv the args
  218. * rname file with remarks about the entry
  219. * bname file containing how prog.c should be built
  220. * pname the obfuscated program source file
  221. * oname ioccc entry output file
  222. *
  223. * Given the command line args, this function parses them and sets the
  224. * required name flags. This function will return only if the command
  225. * line syntax is correct.
  226. */
  227. void
  228. parse_args(int argc, char **argv, char **rname,
  229. char **bname, char **pname, char **oname)
  230. {
  231. char *optarg; /* -flag option operand */
  232. int flagname; /* the name of the -flag */
  233. int i;
  234. /*
  235. * Not everyone has getopt, so we must parse args by hand.
  236. */
  237. program = argv[0];
  238. for (i=1; i < argc; ++i) {
  239. /* determine the flagname */
  240. if (argv[i][0] != '-') {
  241. usage(1);
  242. /*NOTREACHED*/
  243. }
  244. flagname = (int)argv[i][1];
  245. /* determine the flag's operand */
  246. if (flagname != '\0' && argv[i][2] != '\0') {
  247. optarg = &argv[i][2];
  248. } else {
  249. if (i+1 >= argc) {
  250. usage(2);
  251. /*NOTREACHED*/
  252. } else {
  253. optarg = argv[++i];
  254. }
  255. }
  256. /* save the flag's operand in the correct global variable */
  257. switch (flagname) {
  258. case 'r':
  259. *rname = optarg;
  260. break;
  261. case 'b':
  262. *bname = optarg;
  263. break;
  264. case 'p':
  265. *pname = optarg;
  266. break;
  267. case 'o':
  268. *oname = optarg;
  269. break;
  270. default:
  271. usage(3);
  272. /*NOTREACHED*/
  273. }
  274. }
  275. /*
  276. * verify that we have all of the required flags
  277. */
  278. if (*rname == NULL || *bname == NULL || *pname == NULL || *oname == NULL) {
  279. usage(4);
  280. /*NOTREACHED*/
  281. }
  282. return;
  283. }
  284. /*
  285. * usage - print a usage message and exit
  286. *
  287. * usage:
  288. * exitval exit with this value
  289. *
  290. * This function does not return.
  291. */
  292. void
  293. usage(int exitval)
  294. {
  295. fprintf(stderr,
  296. "usage: %s -r remarks -b build -p prog.c -o ioccc.entry\n\n", program);
  297. fprintf(stderr, "\t-r remarks\tfile with remarks about the entry\n");
  298. fprintf(stderr, "\t-b build\tfile containing how prog.c should be built\n");
  299. fprintf(stderr, "\t-p prog.c\tthe obfuscated program source file\n");
  300. fprintf(stderr, "\t-o ioccc.entry\tioccc entry output file\n");
  301. exit(exitval);
  302. }
  303. /*
  304. * open_remark - open/check the remark file
  305. *
  306. * usage:
  307. * filename remark filename
  308. *
  309. * The remark file should be indented by 4 spaces, and should not extend
  310. * beyond column MAX_COL. These are not requirements, so we only warn.
  311. *
  312. * This function returns NULL on I/O or format error.
  313. */
  314. FILE *
  315. open_remark(char *filename)
  316. {
  317. FILE *stream; /* the opened file stream */
  318. char buf[BUFSIZ+1]; /* input buffer */
  319. int toolong=0; /* number of lines that are too long */
  320. int non_indent=0; /* number of lines not indented by 4 spaces */
  321. /*
  322. * open the remark input file
  323. */
  324. stream = fopen(filename, "r");
  325. if (stream == NULL) {
  326. fprintf(stderr, "%s: cannot open remark file: %s: ",
  327. program, filename);
  328. perror("");
  329. return(NULL);
  330. }
  331. /*
  332. * look at each line
  333. */
  334. while (fgets(buf, BUFSIZ, stream) != NULL) {
  335. /* count lines that do not start with 4 spaces */
  336. if (buf[0] != '\n' && strncmp(buf, " ", 4) != 0) {
  337. ++non_indent;
  338. }
  339. /* count long lines */
  340. if (col_len(buf) > MAX_COL) {
  341. /* found a line that is too long */
  342. ++toolong;
  343. }
  344. }
  345. /* watch for I/O errors */
  346. check_io(stream, filename, EOF_OK);
  347. /* note long lines if needed */
  348. if (toolong > 0) {
  349. fprintf(stderr,
  350. "%s: WARNING: %d line(s) from %s extend beyond the 80th column\n",
  351. program, toolong, filename);
  352. fprintf(stderr,
  353. "%s: This is ok, but it would be nice to avoid\n\n",
  354. program);
  355. }
  356. /* note non-indented lines, if needed */
  357. if (non_indent > 0) {
  358. fprintf(stderr,
  359. "%s: WARNING: %d line(s) from %s are not indented by 4 spaces\n",
  360. program, non_indent, filename);
  361. fprintf(stderr,
  362. "%s: This is ok, but it would be nice to avoid\n\n",
  363. program);
  364. }
  365. /* return the open file */
  366. rewind(stream);
  367. return(stream);
  368. }
  369. /*
  370. * open_build - open/check the build file
  371. *
  372. * usage:
  373. * filename build filename
  374. *
  375. * The how to build file must not be longer than MAX_BUILD_SIZE bytes.
  376. *
  377. * This function returns NULL on I/O or size error.
  378. */
  379. FILE *
  380. open_build(char *filename)
  381. {
  382. FILE *stream; /* the opened file stream */
  383. struct stat statbuf; /* the status of the open file */
  384. /*
  385. * open the how to build input file
  386. */
  387. stream = fopen(filename, "r");
  388. if (stream == NULL) {
  389. fprintf(stderr, "%s: cannot open how to build file: %s: ",
  390. program, filename);
  391. perror("");
  392. return(NULL);
  393. }
  394. /*
  395. * determine the size of the file
  396. */
  397. if (fstat(fileno(stream), &statbuf) < 0) {
  398. fprintf(stderr, "%s: cannot stat how to build file: %s: ",
  399. program, filename);
  400. perror("");
  401. return(NULL);
  402. }
  403. if (statbuf.st_size > MAX_BUILD_SIZE) {
  404. fprintf(stderr,
  405. "%s: FATAL: the how to build file: %s, is %ld bytes long\n",
  406. program, filename, (long) statbuf.st_size);
  407. fprintf(stderr,
  408. "%s: it may not be longer than %d bytes\n",
  409. program, MAX_BUILD_SIZE);
  410. return(NULL);
  411. }
  412. /* return the open file */
  413. return(stream);
  414. }
  415. /*
  416. * open_program - open/check the program source file
  417. *
  418. * usage:
  419. * filename source filename
  420. *
  421. * The program source file must be <= 3217 bytes. The number of
  422. * non-whitespace and }{; chars not followed by whitespace must
  423. * be <= 1536 bytes.
  424. *
  425. * This function returns NULL on I/O or size error.
  426. */
  427. FILE *
  428. open_program(char *filename)
  429. {
  430. FILE *stream; /* the opened file stream */
  431. struct stat statbuf; /* the status of the open file */
  432. int count; /* special count size */
  433. int c; /* the character read */
  434. /*
  435. * open the program source input file
  436. */
  437. stream = fopen(filename, "r");
  438. if (stream == NULL) {
  439. fprintf(stderr, "%s: cannot open program source file: %s: ",
  440. program, filename);
  441. perror("");
  442. exit(7);
  443. }
  444. /*
  445. * determine the size of the file
  446. */
  447. if (fstat(fileno(stream), &statbuf) < 0) {
  448. fprintf(stderr, "%s: cannot stat program source file: %s: ",
  449. program, filename);
  450. perror("");
  451. return(NULL);
  452. }
  453. if (statbuf.st_size > MAX_PROGRAM_SIZE) {
  454. fprintf(stderr,
  455. "%s: FATAL: the program source file: %s, is %ld bytes long\n",
  456. program, filename, (long) statbuf.st_size);
  457. fprintf(stderr,
  458. "%s: it may not be longer than %d bytes\n",
  459. program, MAX_PROGRAM_SIZE);
  460. return(NULL);
  461. }
  462. /*
  463. * count the non-whitespace, non {}; followed by whitespace chars
  464. */
  465. count = 0;
  466. c = 0;
  467. while ((c=fgetc(stream)) != EOF) {
  468. /* look at non-whitespace */
  469. if (!isascii(c) || !isspace(c)) {
  470. switch (c) {
  471. case '{': /* count if not followed by EOF or whitespace */
  472. case '}':
  473. case ';':
  474. /* peek at next char */
  475. c = fgetc(stream);
  476. if (c != EOF && isascii(c) && !isspace(c)) {
  477. /* not followed by whitespace or EOF, count it */
  478. ungetc(c, stream);
  479. ++count;
  480. }
  481. break;
  482. default:
  483. ++count;
  484. break;
  485. }
  486. }
  487. }
  488. /* watch for I/O errors */
  489. check_io(stream, filename, EOF_OK);
  490. /* look at the special size */
  491. if (count > MAX_PROGRAM_SIZE2) {
  492. fprintf(stderr,
  493. "%s: FATAL: the number of bytes that are non-whitespace, and\n",
  494. program);
  495. fprintf(stderr,
  496. "%s: that are not '{', '}', ';' followed by whitespace\n",
  497. program);
  498. fprintf(stderr,
  499. "%s: or EOF must be <= %d bytes\n",
  500. program, MAX_PROGRAM_SIZE2);
  501. fprintf(stderr,
  502. "%s: in %s, %d bytes were found\n",
  503. program, filename, count);
  504. return(NULL);
  505. }
  506. /* return the open file */
  507. rewind(stream);
  508. return(stream);
  509. }
  510. /*
  511. * open_output - open/check the entry output file
  512. *
  513. * usage:
  514. * filename output filename
  515. *
  516. * This function returns NULL on open error.
  517. */
  518. FILE *
  519. open_output(char *filename)
  520. {
  521. FILE *stream; /* the opened file stream */
  522. /*
  523. * open the ioccc entry output file
  524. */
  525. stream = fopen(filename, "w");
  526. if (stream == NULL) {
  527. fprintf(stderr, "%s: cannot open ioccc entry file for output: %s: ",
  528. program, filename);
  529. perror("");
  530. exit(8);
  531. }
  532. /* return the open file */
  533. return(stream);
  534. }
  535. /*
  536. * output_entry - output the ---entry--- section
  537. *
  538. * usage:
  539. * output entry's output file stream
  540. * oname name of the output file
  541. *
  542. * Read the needed information form stdin, and write the entry section.
  543. */
  544. void
  545. output_entry(FILE *output, char *oname)
  546. {
  547. char title[MAX_TITLE_LEN+1+1]; /* the entry's title */
  548. char buf[MAX_COL+1+1]; /* I/O buffer */
  549. int entry=0; /* entry number */
  550. int ret; /* fields processed by fscanf */
  551. int ok_line=0; /* 0 => the line is not ok */
  552. char skip; /* input to skip */
  553. time_t epoch_sec; /* seconds since the epoch */
  554. char *p;
  555. /*
  556. * write the start of the section
  557. */
  558. fprintf(output, "---entry---\n");
  559. check_io(output, oname, EOF_NOT_OK);
  560. /*
  561. * write the rule year
  562. */
  563. fprintf(output, "rule:\t%d\n", RULE_YEAR);
  564. check_io(output, oname, EOF_NOT_OK);
  565. /* determine if this is a fix */
  566. printf("Is this a fix, update or resubmittion to a ");
  567. printf("previous entry (enter y or n)? ");
  568. while (get_line(buf, 1+1, 0) <= 0 || !(buf[0]=='y' || buf[0]=='n')) {
  569. printf("\nplease answer y or n: ");
  570. }
  571. if (buf[0] == 'y') {
  572. fprintf(output, "fix:\ty\n");
  573. check_io(output, oname, EOF_NOT_OK);
  574. printf("\nBe sure that the title and entry number that you give\n");
  575. printf("are the same of as the entry you are replacing\n");
  576. } else {
  577. fprintf(output, "fix:\tn\n");
  578. check_io(output, oname, EOF_NOT_OK);
  579. }
  580. /*
  581. * write the title
  582. */
  583. printf("\nThe first character of your title should match [a-zA-Z0-9_=]\n");
  584. printf("The next 0 to %d characters should match [a-zA-Z0-9_=+-]\n\n",
  585. MAX_TITLE_LEN-1);
  586. printf("It is suggested, but not required, that the title should\n");
  587. printf("incorporate your username; in the\n");
  588. printf("case of multiple authors, consider using parts of the usernames\n");
  589. printf("of the authors.\n\n");
  590. printf("enter your title: ");
  591. do {
  592. /* prompt and read a line */
  593. if ((ok_line = get_line(title, MAX_TITLE_LEN+1, MAX_COL-9)) <= 0) {
  594. printf("\ntitle is too long, please re-enter: ");
  595. continue;
  596. }
  597. /* verify the pattern, not everyone has regexp, so do it by hand */
  598. if (!isascii((int)title[0]) ||
  599. !(isalnum((int)title[0]) || title[0] == '_' || title[0] == '=')) {
  600. printf("\ninvalid first character in the title\n\n");
  601. printf("enter your title: ");
  602. ok_line = 0;
  603. } else {
  604. for (p=(&title[1]); *p != '\0' && *p != '\n'; ++p) {
  605. if (!isascii((int)*p) ||
  606. !(isalnum((int)*p) ||
  607. *p == '_' || *p == '=' || *p == '+' || *p == '-')) {
  608. printf("\ninvalid character in the title\n\n");
  609. printf("enter your title: ");
  610. ok_line = 0;
  611. }
  612. }
  613. }
  614. } while (ok_line <= 0);
  615. fprintf(output, "title:\t%s", title);
  616. check_io(output, oname, EOF_NOT_OK);
  617. /*
  618. * write the entry number
  619. */
  620. printf("\nEach person may submit up to %d entries per year.\n\n",
  621. MAX_ENTRY);
  622. printf("enter an entry number from 0 to %d inclusive: ", MAX_ENTRY-1);
  623. do {
  624. /* get a valid input line */
  625. fflush(stdout);
  626. ret = fscanf(stdin, "%d[\n]", &entry);
  627. check_io(stdin, "stdin", EOF_NOT_OK);
  628. /* skip over input until newline is found */
  629. do {
  630. skip = fgetc(stdin);
  631. check_io(stdin, "stdin", EOF_NOT_OK);
  632. if (skip != '\n') {
  633. /* bad text in input, invalidate entry number */
  634. entry = -1;
  635. }
  636. } while (skip != '\n');
  637. /* check if we have a number, and if it is in range */
  638. if (ret != 1 || entry < 0 || entry > MAX_ENTRY-1) {
  639. printf(
  640. "\nThe entry number must be between 0 and %d inclusive\n\n",
  641. MAX_ENTRY-1);
  642. printf("enter the entry number: ");
  643. }
  644. } while (ret != 1 || entry < 0 || entry > MAX_ENTRY-1);
  645. fprintf(output, "entry:\t%d\n", entry);
  646. check_io(output, oname, EOF_NOT_OK);
  647. /*
  648. * write the submission date
  649. */
  650. /* returns a newline */
  651. epoch_sec = time(NULL);
  652. fprintf(output, "date:\t%s", asctime(gmtime(&epoch_sec)));
  653. check_io(output, oname, EOF_NOT_OK);
  654. /*
  655. * write the OS/machine host information
  656. */
  657. printf(
  658. "\nEnter the machine(s) and OS(s) under which your entry was tested.\n");
  659. output_till_dot(output, oname, "host:");
  660. }
  661. /*
  662. * output_remark - output the ---remark--- section
  663. *
  664. * usage:
  665. * output entry's output file stream
  666. * oname name of the output file
  667. * remark stream to the file containing remark text
  668. * rname name of the remark file
  669. *
  670. * Read the needed information form stdin, and write the entry section.
  671. */
  672. void
  673. output_remark(FILE *output, char *oname, FILE *remark, char *rname)
  674. {
  675. char buf[BUFSIZ+1]; /* input/output buffer */
  676. /*
  677. * write the start of the section
  678. */
  679. fprintf(output, "---remark---\n");
  680. check_io(output, oname, EOF_NOT_OK);
  681. /*
  682. * copy the remark file to the section
  683. */
  684. while (fgets(buf, BUFSIZ, remark) != NULL) {
  685. fputs(buf, output);
  686. check_io(output, oname, EOF_NOT_OK);
  687. }
  688. check_io(remark, rname, EOF_OK);
  689. /* be sure that the remark section ends with a newline */
  690. if (buf[strlen(buf)-1] != '\n') {
  691. fputc('\n', output);
  692. check_io(output, oname, EOF_NOT_OK);
  693. }
  694. }
  695. /*
  696. * output_author - output the ---author--- section
  697. *
  698. * usage:
  699. * output entry's output file stream
  700. * oname name of the output file
  701. *
  702. * Read the needed information from stdin, and write the author section.
  703. * If multiple authors exist, multiple author sections will be written.
  704. */
  705. void
  706. output_author(FILE *output, char *oname)
  707. {
  708. char buf[MAX_COL+1+1]; /* I/O buffer */
  709. int more_auths; /* TRUE => more authors to note */
  710. int auth_cnt=0; /* number of authors processed */
  711. /*
  712. * prompt the user for the author section
  713. */
  714. printf("\nEnter information about each author. If your entry is after\n");
  715. printf("%s and before the contest deadline, the judges\n", START_DATE);
  716. printf("will attempt to EMail back a confirmation to the first author\n");
  717. /*
  718. * place author information for each author in an individual section
  719. */
  720. do {
  721. /* write the start of the section */
  722. fprintf(output, "---author---\n");
  723. check_io(output, oname, EOF_NOT_OK);
  724. /* write the author */
  725. printf("\nAuthor #%d name: ", ++auth_cnt);
  726. while (get_line(buf, MAX_COL+1, MAX_COL-9) <= 0) {
  727. printf("\nname too long, please re-enter: ");
  728. }
  729. fprintf(output, "name:\t%s", buf);
  730. check_io(output, oname, EOF_NOT_OK);
  731. /* write the organization */
  732. printf("\nEnter the School/Company/Organization of author #%d\n",
  733. auth_cnt);
  734. printf("\nAuthor #%d org: ", auth_cnt);
  735. while (get_line(buf, MAX_COL+1, MAX_COL-9) <= 0) {
  736. printf("\nline too long, please re-enter: ");
  737. }
  738. fprintf(output, "org:\t%s", buf);
  739. check_io(output, oname, EOF_NOT_OK);
  740. /* write the address */
  741. printf(
  742. "\nEnter the postal address for author #%d. Be sure to include\n",
  743. auth_cnt);
  744. printf("your country and do not include your name.\n");
  745. output_till_dot(output, oname, "addr:");
  746. /* write the EMail address */
  747. printf(
  748. "\nEnter the EMail address for author #%d. Use an address from\n",
  749. auth_cnt);
  750. printf(
  751. "a registered domain or well known site. If you give several\n");
  752. printf("forms, list them one per line.\n");
  753. output_till_dot(output, oname, "email:");
  754. /* write the home page URL */
  755. printf(
  756. "\nEnter the fully qualified home page URL for author #%d\n",
  757. auth_cnt);
  758. printf("including the http: part or type none: ");
  759. while (get_line(buf, MAX_COL+1, MAX_COL-9) <= 0 ||
  760. (strncmp(buf, "http://", sizeof("http://")-1) != 0 &&
  761. strcmp(buf, "none\n") != 0)) {
  762. printf("\nURL too long, does not begin with http:// or\n");
  763. printf("is not the word none\n");
  764. }
  765. fprintf(output, "url:\t%s", buf);
  766. check_io(output, oname, EOF_NOT_OK);
  767. /* write the anonymous status */
  768. printf("\nShould author #%d remain anonymous (enter y or n)? ",
  769. auth_cnt);
  770. while (get_line(buf, 1+1, 0) <= 0 || !(buf[0]=='y' || buf[0]=='n')) {
  771. printf("\nplease answer y or n: ");
  772. }
  773. fprintf(output, "anon:\t%s", buf);
  774. check_io(output, oname, EOF_NOT_OK);
  775. /* determine if there is another author */
  776. printf("\nIs there another author (enter y or n)? ");
  777. while (get_line(buf, 1+1, 0) <= 0 || !(buf[0]=='y' || buf[0]=='n')) {
  778. printf("\nplease answer y or n: ");
  779. }
  780. if (buf[0] == 'y') {
  781. more_auths = TRUE;
  782. } else {
  783. more_auths = FALSE;
  784. }
  785. } while (more_auths == TRUE);
  786. return;
  787. }
  788. /*
  789. * output_info - output the ---info--- section(s)
  790. *
  791. * usage:
  792. * output entry's output file stream
  793. * oname name of the output file
  794. *
  795. * Read the needed information from stdin, and write the info section.
  796. * If multiple info files exist, multiple info sections will be written.
  797. */
  798. void
  799. output_info(FILE *output, char *oname)
  800. {
  801. char infoname[MAX_FILE_LEN+1]; /* filename buffer */
  802. char yorn[1+1]; /* y or n answer */
  803. char *uuname; /* name to uuencode as */
  804. FILE *infile; /* info file stream */
  805. /*
  806. * prompt the user for info information
  807. */
  808. printf("\nInfo files should be used only to supplement your entry.\n");
  809. printf("For example, info files may provide sample input or detailed\n");
  810. printf("information about your entry. Because they are supplemental,\n");
  811. printf("the entry should not require them to exist.\n\n");
  812. /*
  813. * while there is another info file to save, uuencode it
  814. */
  815. printf("Do you have a info file to include (enter y or n)? ");
  816. while (get_line(yorn, 1+1, 0) <= 0 || !(yorn[0]=='y' || yorn[0]=='n')) {
  817. printf("\nplease answer y or n: ");
  818. }
  819. while (yorn[0] == 'y') {
  820. /* read the filename */
  821. printf("\nEnter the info filename: ");
  822. while (get_line(infoname, MAX_FILE_LEN+1, 0) <= 0) {
  823. printf("\nInfo filename too long, please re-enter: ");
  824. }
  825. /* compute the basename of the info filename */
  826. /* remove the trailing newline */
  827. uuname = &infoname[strlen(infoname)-1];
  828. *uuname = '\0';
  829. /* avoid rindex/shrrchr compat issues, do it by hand */
  830. for (--uuname; uuname > infoname; --uuname) {
  831. if (*uuname == '/') {
  832. ++uuname;
  833. break;
  834. }
  835. }
  836. /* attempt to open the info file */
  837. infile = fopen(infoname, "r");
  838. if (infile == NULL) {
  839. fprintf(stderr, "\n%s: cannot open info file: %s: ",
  840. program, infoname);
  841. perror("");
  842. continue;
  843. }
  844. /*
  845. * write the start of the section
  846. */
  847. fprintf(output, "---info---\n");
  848. check_io(output, oname, EOF_NOT_OK);
  849. /* uuencode the info file */
  850. uuencode(output, oname, infile, infoname, UUINFO_MODE, uuname);
  851. printf("\nDo you have another info file to include (enter y or n)? ");
  852. while (get_line(yorn, 1+1, 0) <= 0 || !(yorn[0]=='y' || yorn[0]=='n')) {
  853. printf("\nplease answer y or n: ");
  854. }
  855. };
  856. return;
  857. }
  858. /*
  859. * output_build - output the ---build--- section
  860. *
  861. * usage:
  862. * output entry's output file stream
  863. * oname name of the output file
  864. * build open build file stream
  865. * bname name of the build file
  866. *
  867. * Read the needed information from stdin, and write the build section.
  868. */
  869. void
  870. output_build(FILE *output, char *oname, FILE *build, char *bname)
  871. {
  872. /*
  873. * write the start of the section
  874. */
  875. fprintf(output, "---build---\n");
  876. check_io(output, oname, EOF_NOT_OK);
  877. /*
  878. * uuencode the program file
  879. */
  880. uuencode(output, oname, build, bname, UUBUILD_MODE, UUBUILD_NAME);
  881. return;
  882. }
  883. /*
  884. * output_program - output the ---program--- section
  885. *
  886. * usage:
  887. * output entry's output file stream
  888. * oname name of the output file
  889. * prog open program stream
  890. * pname name of program file
  891. *
  892. * Read the needed information form stdin, and write the program section.
  893. */
  894. void
  895. output_program(FILE *output, char *oname, FILE *prog, char *pname)
  896. {
  897. /*
  898. * write the start of the section
  899. */
  900. fprintf(output, "---program---\n");
  901. check_io(output, oname, EOF_NOT_OK);
  902. /*
  903. * uuencode the program file
  904. */
  905. uuencode(output, oname, prog, pname, UUPROG_MODE, UUPROG_NAME);
  906. return;
  907. }
  908. /*
  909. * output_end - output the ---end--- section
  910. *
  911. * usage:
  912. * output entry's output file stream
  913. * oname name of the output file
  914. *
  915. * Read the needed information form stdin, and write the 'end section'.
  916. */
  917. void
  918. output_end(FILE *output, char *oname)
  919. {
  920. /*
  921. * write the final section terminator
  922. */
  923. fprintf(output, "---end---\n");
  924. check_io(output, oname, EOF_NOT_OK);
  925. return;
  926. }
  927. /*
  928. * get_line - get an answer from stdin
  929. *
  930. * usage:
  931. * buf input buffer
  932. * siz length of input, including the newline
  933. * maxcol max col allowed, 0 => disable check
  934. *
  935. * This function will flush stdout, in case a prompt is pending, and
  936. * read in the answer.
  937. *
  938. * This function returns 0 if the line is too long, of the length of the
  939. * line (including the newline) of the line was ok. This function does
  940. * not return if ERROR or EOF.
  941. */
  942. int
  943. get_line(char *buf, int siz, int maxcol)
  944. {
  945. int length; /* the length of the input line */
  946. /* flush terminal output */
  947. fflush(stdout);
  948. /* read the line */
  949. if (fgets(buf, siz+1, stdin) == NULL) {
  950. /* report the problem */
  951. check_io(stdin, "stdin", EOF_NOT_OK);
  952. }
  953. /* look for the newline */
  954. length = strlen(buf);
  955. if (buf[length-1] != '\n') {
  956. int eatchar; /* the char being eaten */
  957. /* no newline found, line must be too long, eat the rest of the line */
  958. do {
  959. eatchar = fgetc(stdin);
  960. } while (eatchar != EOF && eatchar != '\n');
  961. check_io(stdin, "stdin", EOF_NOT_OK);
  962. /* report the situation */
  963. return 0;
  964. }
  965. /* watch for long lines, if needed */
  966. if (maxcol > 0 && (length > maxcol || col_len(buf) > maxcol)) {
  967. /* report the situation */
  968. return 0;
  969. }
  970. /* return length */
  971. return length;
  972. }
  973. /*
  974. * output_till_dot - output a set of lines until '.' by itself is read
  975. *
  976. * usage:
  977. * output entry's output file stream
  978. * oname name of the output file
  979. * leader the lead text for the first line
  980. *
  981. * This routine will read a set of lines until (but not including)
  982. * a single line with '.' is read. The format of the output is:
  983. *
  984. * leader:\tfirst line
  985. * \tnext line
  986. * \tnext line
  987. * ...
  988. *
  989. * This routine will not return if I/O error or EOF.
  990. */
  991. void
  992. output_till_dot(FILE *output, char *oname, char *leader)
  993. {
  994. char buf[BUFSIZ+1]; /* input buffer */
  995. int count; /* lines read */
  996. int done=FALSE; /* TRUE => finished reading input */
  997. /* instruct the user on how to input */
  998. printf("\nTo end input, enter a line with a single period.\n");
  999. /* read lines until '.' or EOF */
  1000. count = 0;
  1001. while (!done) {
  1002. /* issue the prompt */
  1003. printf("%s\t", (count>0) ? "" : leader);
  1004. fflush(stdout);
  1005. /* get the line */
  1006. if (get_line(buf, BUFSIZ, MAX_COL-9) <= 0) {
  1007. printf("\nline too long, please re-enter:\n\t");
  1008. continue;
  1009. }
  1010. /* note if '.' was read */
  1011. if (strcmp(buf, ".\n") == 0) {
  1012. done = TRUE;
  1013. }
  1014. /* write line if we read something */
  1015. if (!done) {
  1016. fprintf(output, "%s\t%s", (count++>0) ? "" : leader, buf);
  1017. check_io(output, oname, EOF_NOT_OK);
  1018. }
  1019. }
  1020. /* if no lines read, at least output something */
  1021. if (count <= 0) {
  1022. fprintf(output, "%s\t.\n", leader);
  1023. check_io(output, oname, EOF_NOT_OK);
  1024. }
  1025. return;
  1026. }
  1027. /*
  1028. * col_len - determine the highest that a string would reach
  1029. *
  1030. * usage:
  1031. * string the string to examine
  1032. *
  1033. * Given a string, this routine returns that a string would reach
  1034. * if the string were printed at column 1. Tab stops are assumed
  1035. * to start at 9, 17, 25, 33, ...
  1036. */
  1037. int
  1038. col_len(char *string)
  1039. {
  1040. int col; /* current column */
  1041. char *p; /* current char */
  1042. /* scan the string */
  1043. for (col=0, p=string; *p != '\0' && *p != '\n'; ++p) {
  1044. /* note the column shift */
  1045. col = (*p=='\t') ? 1+((col+8)/8*8) : col+1;
  1046. }
  1047. if (*p == '\n') {
  1048. --col;
  1049. }
  1050. /* return the highest column */
  1051. return col;
  1052. }
  1053. /*
  1054. * check_io - check for EOF or I/O error on a stream
  1055. *
  1056. * usage:
  1057. * stream the stream to check
  1058. * name the name of this stream
  1059. * eof_ok EOF_OK or EOF_NOT_OK
  1060. *
  1061. * Does not return if EOF or I/O error.
  1062. */
  1063. void
  1064. check_io(FILE *stream, char *name, int eof_ok)
  1065. {
  1066. /* test for I/O error */
  1067. if (ferror(stream)) {
  1068. fprintf(stderr, "%s: error on %s: ", program, name);
  1069. perror("");
  1070. exit(1);
  1071. /* test for EOF */
  1072. } else if (eof_ok == EOF_NOT_OK && feof(stream)) {
  1073. fprintf(stderr, "%s: EOF on %s\n", program, name);
  1074. exit(1);
  1075. }
  1076. return;
  1077. }
  1078. /*
  1079. * uuencode - uuencode a file
  1080. *
  1081. * usage:
  1082. * output output file stream
  1083. * oname output filename
  1084. * infile input file stream
  1085. * iname input filename
  1086. * umode the mode to put on the uuencode file
  1087. * uname name to put on the uuencode file
  1088. *
  1089. * Perform the uuencoding process identical to the process performed
  1090. * by the uuencode(1) utility.
  1091. *
  1092. * This routine implements the algorithm described in the uuencode(5)
  1093. * 4.3BSD Reno man page.
  1094. */
  1095. void
  1096. uuencode(FILE *output, char *oname, FILE *infile,
  1097. char *iname, int umode, char *uname)
  1098. {
  1099. char buf[UUENCODE_LEN+1]; /* the uuencode buffer */
  1100. int read_len; /* actual number of chars read */
  1101. int val; /* 6 bit chunk from buf */
  1102. char filler='\0'; /* filler uuencode pad text */
  1103. char *p;
  1104. /*
  1105. * output the initial uuencode header
  1106. */
  1107. fprintf(output, "begin %o %s\n", umode, uname);
  1108. check_io(output, oname, EOF_NOT_OK);
  1109. /*
  1110. * clear out the input buffer
  1111. */
  1112. for (p=buf; p < &buf[sizeof(buf)/sizeof(buf[0])]; ++p) {
  1113. *p = '\0';
  1114. }
  1115. /*
  1116. * We will process UUENCODE_LEN chars at a time, forming
  1117. * a single output line each time.
  1118. */
  1119. while ((read_len=fread(buf,sizeof(buf[0]),UUENCODE_LEN,infile)) > 0) {
  1120. /*
  1121. * the first character is the length character
  1122. */
  1123. fputc(UUENCODE(read_len), output);
  1124. check_io(output, oname, EOF_NOT_OK);
  1125. /*
  1126. * We will convert 24 bits at a time. Thus we will convert
  1127. * 3 sets of 8 bits into 4 sets of uuencoded 6 bits.
  1128. */
  1129. for (p=buf; read_len>0; read_len-=3, p+=3) {
  1130. /* bits 0 to 5 */
  1131. val = (p[0]>>2)&0x3f;
  1132. fputc(UUENCODE(val), output);
  1133. check_io(output, oname, EOF_NOT_OK);
  1134. /* bits 6 to 11 */
  1135. val = ((p[0]<<4)&0x30) | ((p[1]>>4)&0x0f);
  1136. fputc(UUENCODE(val), output);
  1137. check_io(output, oname, EOF_NOT_OK);
  1138. /* bits 12 to 17 */
  1139. val = ((p[1]<<2)&0x3c) | ((p[2]>>6)&0x03);
  1140. fputc(UUENCODE(val), output);
  1141. check_io(output, oname, EOF_NOT_OK);
  1142. /* bits 18 to 23 */
  1143. val = p[2]&0x3f;
  1144. fputc(UUENCODE(val), output);
  1145. check_io(output, oname, EOF_NOT_OK);
  1146. }
  1147. /* end of UUENCODE_LEN line */
  1148. fputc('\n', output);
  1149. check_io(output, oname, EOF_NOT_OK);
  1150. /*
  1151. * clear out the input buffer (don't depend on bzero() or memset())
  1152. */
  1153. for (p=buf; p < &buf[sizeof(buf)/sizeof(buf[0])]; ++p) {
  1154. *p = '\0';
  1155. }
  1156. }
  1157. /* check the last read on the input file */
  1158. check_io(infile, iname, EOF_OK);
  1159. /* write end of uuencode file */
  1160. fprintf(output, "%c\nend\n", UUENCODE(filler));
  1161. check_io(output, oname, EOF_NOT_OK);
  1162. }