PageRenderTime 28ms CodeModel.GetById 40ms RepoModel.GetById 0ms app.codeStats 0ms

/2001/mkentry.c

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