PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/config.c

https://repo.or.cz/afunbrick.git
C | 194 lines | 179 code | 15 blank | 0 comment | 52 complexity | 8f9ebd4d81739462afa118f84830d598 MD5 | raw file
Possible License(s): GPL-3.0
  1. #include <stddef.h>
  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #define OPTPARSE_IMPLEMENTATION
  8. #define OPTPARSE_API static
  9. #include <optparse/optparse.h>
  10. #include "config.h"
  11. void afb_config_init(struct afb_config* config)
  12. {
  13. config->std = STD_BRAINFUCK;
  14. config->print = false;
  15. config->debug = false;
  16. config->help = false;
  17. config->bin = NULL;
  18. config->in_filename = NULL;
  19. config->out_filename = NULL;
  20. config->err_filename = NULL;
  21. config->in_stream = stdin;
  22. config->out_stream = stdout;
  23. config->err_stream = stderr;
  24. config->wordsize = 0;
  25. config->memsize = 0;
  26. }
  27. void afb_config_free(struct afb_config* config)
  28. {
  29. if (config->in_stream) fclose(config->in_stream);
  30. if (config->out_stream) fclose(config->out_stream);
  31. if (config->err_stream) fclose(config->err_stream);
  32. }
  33. static int set_standard(struct afb_config* config, const char* arg)
  34. {
  35. if (0 == strcmp(arg, "bf")) {
  36. config->std = STD_BRAINFUCK;
  37. } else if (0 == strcmp(arg, "ook")) {
  38. config->std = STD_OOK;
  39. } else if (0 == strcmp(arg, "bf++")) {
  40. config->std = STD_BRAINFUCKPP;
  41. } else if (0 == strcmp(arg, "bf--")) {
  42. config->std = STD_BRAINFUCKMM;
  43. } else if (0 == strcmp(arg, "*bf")) {
  44. config->std = STD_PTRBRAINFUCK;
  45. } else if (0 == strcmp(arg, "lcbf")) {
  46. config->std = STD_LCBF;
  47. } else if (0 == strcmp(arg, "mndb")) {
  48. config->std = STD_MNDB;
  49. } else if (0 == strcmp(arg, "brainfork")) {
  50. config->std = STD_BRAINFORK;
  51. } else if (0 == strcmp(arg, "bfp3")) {
  52. config->std = STD_BFP3;
  53. } else {
  54. fprintf(config->err_stream, "%s: standard \"%s\" does not exist\n", config->bin, arg);
  55. return 1 << 0;
  56. }
  57. return 0;
  58. }
  59. static int set_wordsize(struct afb_config* config, const char* arg)
  60. {
  61. unsigned long ws = strtoul(arg, NULL, 10);
  62. if ((0 < ws) && (ws <= 64)) {
  63. config->wordsize = ws;
  64. return 0;
  65. } else {
  66. fprintf(config->err_stream, "%s: invalid wordsize: %s (1-64 expected)\n", config->bin, arg);
  67. return 1 << 1;
  68. }
  69. }
  70. static int set_memsize(struct afb_config* config, const char* arg)
  71. {
  72. unsigned long ms = strtoul(arg, NULL, 10);
  73. if (ms != 0) {
  74. config->memsize = ms;
  75. return 0;
  76. } else {
  77. fprintf(config->err_stream, "%s: invalid memory size (must be >0)\n", config->bin);
  78. return 1 << 1;
  79. }
  80. }
  81. int afb_config_parse(struct afb_config* config, char** argv)
  82. {
  83. int res = 0;
  84. config->bin = argv[0];
  85. struct optparse_long longopts[] = {
  86. { "help", 'h', OPTPARSE_NONE },
  87. { "print", 'p', OPTPARSE_NONE },
  88. { "debug", 'd', OPTPARSE_NONE },
  89. { "std", 's', OPTPARSE_REQUIRED },
  90. { "wordsize", 'w', OPTPARSE_REQUIRED },
  91. { "memsize", 'm', OPTPARSE_REQUIRED },
  92. { NULL, 0, 0 }
  93. };
  94. int option;
  95. struct optparse options;
  96. optparse_init(&options, argv);
  97. while ((option = optparse_long(&options, longopts, NULL)) != -1) {
  98. switch (option) {
  99. case 'p':
  100. config->print = true;
  101. break;
  102. case 'd':
  103. config->debug = true;
  104. break;
  105. case 's':
  106. res |= set_standard(config, options.optarg);
  107. break;
  108. case 'w':
  109. res |= set_wordsize(config, options.optarg);
  110. break;
  111. case 'm':
  112. res |= set_memsize(config, options.optarg);
  113. break;
  114. case 'h':
  115. config->help = true;
  116. break;
  117. case '?':
  118. fprintf(config->err_stream, "%s: %s\n", config->bin, options.errmsg);
  119. res |= 1 << 2;
  120. }
  121. }
  122. char* arg;
  123. while ((arg = optparse_arg(&options))) {
  124. if (config->in_filename == NULL) {
  125. config->in_filename = arg;
  126. } else {
  127. fprintf(config->err_stream, "%s: unexpected argument \"%s\", input file already set (\"%s\")\n", config->bin, arg, config->in_filename);
  128. res |= 1 << 3;
  129. }
  130. }
  131. return res;
  132. }
  133. int afb_config_open_streams(struct afb_config* config)
  134. {
  135. int res = 0;
  136. if (config->in_filename != NULL) {
  137. config->in_stream = fopen(config->in_filename, "r");
  138. if (!config->in_stream) {
  139. fprintf(config->err_stream, "%s: cannot open file \"%s\": %s\n", config->bin, config->in_filename, strerror(errno));
  140. res |= 1 << 0;
  141. }
  142. }
  143. if (config->out_filename != NULL) {
  144. config->out_stream = fopen(config->out_filename, "r");
  145. if (!config->out_stream) {
  146. fprintf(config->err_stream, "%s: cannot open file \"%s\": %s\n", config->bin, config->out_filename, strerror(errno));
  147. res |= 1 << 1;
  148. }
  149. }
  150. if (config->err_filename != NULL) {
  151. config->err_stream = fopen(config->err_filename, "r");
  152. if (!config->err_stream) {
  153. fprintf(config->err_stream, "%s: cannot open file \"%s\": %s\n", config->bin, config->err_filename, strerror(errno));
  154. res |= 1 << 2;
  155. }
  156. }
  157. return res;
  158. }
  159. void afb_config_usage(struct afb_config* config)
  160. {
  161. fprintf(config->err_stream,
  162. "usage:\n"
  163. "\n"
  164. " %s [options] [input file]\n"
  165. "\n"
  166. " -h --help\n"
  167. " print print this help message\n"
  168. " -p --print\n"
  169. " print program after parse (remove comments and line breaks)\n"
  170. " -d --debug\n"
  171. " display memory content after each instruction\n"
  172. " -s --std {bf|ook|bf++|bf--|*bf|lcbf|mndb|brainfork|bfp3}\n"
  173. " set brainf*ck standard\n"
  174. " -w --wordsize {1-64}\n"
  175. " set cellsize in bits\n"
  176. " -m --memsize {0..}\n"
  177. " set memory size in bytes (byte size set by --wordsize)\n",
  178. config->bin);
  179. }