main.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * main.c
  3. *
  4. * Copyright (C) 2015 Alexander Andrejevic <theflash AT sdf DOT lonestar DOT org>
  5. * Copyright (C) 2015 Jason Self <j@jxself.org>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as
  9. * published by the Free Software Foundation, either version 3 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. * SPDX-License-Identifier: AGPL-3.0-or-later
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #include <getopt.h>
  27. #include <time.h>
  28. #include <ctype.h>
  29. #include "config.h"
  30. const int DEFAULT_ZVERSION = 6;
  31. enum { ZVERSION = 11, ZORKID, ZSERIAL };
  32. enum { FAIL = -1, OK = 0, NEED_RESTART = 1 };
  33. static struct option const long_options[] =
  34. {
  35. { "help", no_argument, NULL, 'h' },
  36. { "version", no_argument, NULL, 'V' },
  37. { "output", required_argument, NULL, 'o' },
  38. { "zversion", required_argument, NULL, ZVERSION },
  39. { "zorkid", required_argument, NULL, ZORKID },
  40. { "serial", required_argument, NULL, ZSERIAL },
  41. { NULL, 0, NULL, 0 }
  42. };
  43. typedef struct {
  44. int todo;
  45. } Opcode_dict;
  46. struct
  47. {
  48. int zversion; /* 0 - 8 */
  49. int zorkid; /* 0 - 65535 */
  50. char zserial[7]; /* YYMMDD */
  51. Opcode_dict *opcode_dict;
  52. } Config;
  53. void wrong_arg(const char *err, ...)
  54. {
  55. if (err) {
  56. va_list ap;
  57. va_start(ap, err);
  58. vfprintf(stderr, err, ap);
  59. va_end(ap);
  60. }
  61. fprintf(stderr, "Try `" PACKAGE_NAME " --help' for more information.\n");
  62. exit(1);
  63. }
  64. void print_version()
  65. {
  66. printf( PACKAGE_STRING "\n"
  67. "License AGPLv3+: GNU AGPL version 3 or later\n"
  68. "<http://gnu.org/licenses/agpl.html>\n"
  69. "This is free software: you are free to change and redistribute it.\n"
  70. "There is NO WARRANTY, to the extent permitted by law.\n"
  71. );
  72. exit(0);
  73. }
  74. void print_usage(int failed)
  75. {
  76. printf("Usage: " PACKAGE_NAME " [OPTION...] [FILES...]\n"
  77. "\n"
  78. "--version Display program version and exit\n"
  79. "--help Display this help\n"
  80. "\n"
  81. "--zversion (accepts numbers 1 - 8, defaults to %d if not specified)\n"
  82. "--zorkid (integer between 0 and 65535, defaults to 0 if not specified)\n"
  83. "--serial (six characters of ASCII, defaults to current date\n"
  84. " in the form YYMMDD if not specified)\n",
  85. DEFAULT_ZVERSION
  86. );
  87. exit(failed);
  88. }
  89. void fill_zserial(void)
  90. {
  91. time_t t;
  92. struct tm *timeinfo;
  93. time (&t);
  94. timeinfo = localtime(&t);
  95. strftime (Config.zserial, sizeof(Config.zserial), "%y%m%d", timeinfo);
  96. }
  97. void fill_config(void)
  98. {
  99. bzero(&Config, sizeof(Config));
  100. Config.zversion = DEFAULT_ZVERSION;
  101. fill_zserial();
  102. }
  103. void parse_intarg(int *dest, const char name[], int min, int max, int defval)
  104. {
  105. if (!optarg) {
  106. *dest = defval;
  107. return;
  108. }
  109. int n = atoi(optarg);
  110. if (n >= min && n <= max) {
  111. *dest = n;
  112. return;
  113. }
  114. wrong_arg("Wrong %s value %s, must be integer between %d and %d\n",
  115. name, optarg, min, max);
  116. }
  117. void parse_zserial(void)
  118. {
  119. if (!optarg) {
  120. fill_zserial();
  121. return;
  122. }
  123. size_t n = strlen(optarg);
  124. if (n == sizeof(Config.zserial) - 1) {
  125. char *p = optarg;
  126. while (*p && isalnum(*p))
  127. p++;
  128. if (!*p) { /* ..optarg contains alphanumeric only? */
  129. strncpy(Config.zserial, optarg, sizeof(Config.zserial));
  130. return;
  131. }
  132. }
  133. wrong_arg("Wrong zserial value %s, must be 6 ascii characters\n", optarg);
  134. }
  135. void new_file_suffix(char *result, size_t maxlen, const char *src, const char *newsuffix)
  136. {
  137. strncpy(result, src, maxlen);
  138. char *p = strrchr(result, '.');
  139. if (p && strchr(p, '/'))
  140. p = NULL;
  141. if (p) {
  142. strncpy(p, newsuffix, maxlen - (p - result));
  143. } else {
  144. strncat(result, newsuffix, maxlen);
  145. }
  146. result[maxlen] = 0;
  147. }
  148. char *build_output_filename(const char basename[], const char *suffix)
  149. {
  150. int n = strlen(basename) + strlen(suffix);
  151. char *ofile = malloc(n + 1); /* todo!!! check for NULL. free. */
  152. new_file_suffix(ofile, n, basename, suffix);
  153. return ofile;
  154. }
  155. int init_assembly(void)
  156. {
  157. /* TODO */
  158. return OK;
  159. }
  160. int assembly(void)
  161. {
  162. /* TODO */
  163. return OK;
  164. }
  165. int main(int argc, char *argv[], char *envp[])
  166. {
  167. const char *output_file = NULL;
  168. int i;
  169. fill_config();
  170. int opt = 0;
  171. while ((opt = getopt_long (argc, argv, "hVo:", long_options, NULL)) != -1) {
  172. switch(opt) {
  173. case 'h' : print_usage(0);
  174. case 'V' : print_version();
  175. case 'o' : if (output_file) wrong_arg("Output file must be given once\n");
  176. output_file = optarg;
  177. break;
  178. case ZVERSION: parse_intarg(&Config.zversion, "zversion", 1, 8, 1); break;
  179. case ZORKID : parse_intarg(&Config.zorkid, "zorkid", 0, 0xFFFF, 0); break;
  180. case ZSERIAL : parse_zserial(); break;
  181. default : wrong_arg(0);
  182. }
  183. }
  184. int first_input_file = optind;
  185. if (first_input_file >= argc)
  186. wrong_arg("Missing input file\n");
  187. if (!output_file)
  188. output_file = build_output_filename(argv[first_input_file], ".dat");
  189. // TODO: Everything :)
  190. printf("Input files:\n");
  191. for (i = optind; i < argc; i++)
  192. printf("\t%s\n", argv[i]);
  193. printf("Output file: %s\n\n", output_file);
  194. printf("Config:\n"
  195. "- ZVersion: %d\n"
  196. "- ZorkID: %d\n"
  197. "- ZSerial: %s\n",
  198. Config.zversion, Config.zorkid, Config.zserial
  199. );
  200. init_opcodes(Config.zversion, 0);
  201. while(init_assembly() == OK && assembly() == NEED_RESTART);
  202. /* TODO! List global symbols */
  203. /* TODO! Find abbreviations */
  204. return 0;
  205. }