PageRenderTime 24ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/1993/mkentry.c

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