PageRenderTime 46ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/carray/carray.c

https://gitlab.com/PedroFalcato/sortix
C | 370 lines | 319 code | 30 blank | 21 comment | 164 complexity | a94d942053ecb01f28a0536f348a14b1 MD5 | raw file
  1. /*
  2. * Copyright (c) 2014, 2016 Jonas 'Sortie' Termansen.
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. *
  16. * carray.c
  17. * Convert a binary file to a C array.
  18. */
  19. #include <err.h>
  20. #include <errno.h>
  21. #include <stdbool.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. static void compact_arguments(int* argc, char*** argv)
  26. {
  27. for ( int i = 0; i < *argc; i++ )
  28. {
  29. while ( i < *argc && !(*argv)[i] )
  30. {
  31. for ( int n = i; n < *argc; n++ )
  32. (*argv)[n] = (*argv)[n+1];
  33. (*argc)--;
  34. }
  35. }
  36. }
  37. bool get_option_variable(const char* option, const char** varptr,
  38. const char* arg, int argc, char** argv, int* ip)
  39. {
  40. size_t option_len = strlen(option);
  41. if ( strncmp(option, arg, option_len) != 0 )
  42. return false;
  43. if ( arg[option_len] == '=' )
  44. {
  45. *varptr = arg + option_len + 1;
  46. return true;
  47. }
  48. if ( arg[option_len] != '\0' )
  49. return false;
  50. if ( *ip + 1 == argc )
  51. errx(1, "expected operand after `%s'", option);
  52. *varptr = argv[++*ip];
  53. argv[*ip] = NULL;
  54. return true;
  55. }
  56. #define GET_OPTION_VARIABLE(str, varptr) \
  57. get_option_variable(str, varptr, arg, argc, argv, &i)
  58. void get_short_option_variable(char c, const char** varptr,
  59. const char* arg, int argc, char** argv, int* ip)
  60. {
  61. if ( *(arg+1) )
  62. *varptr = arg + 1;
  63. else
  64. {
  65. if ( *ip + 1 == argc )
  66. errx(1, "option requires an argument -- '%c'", c);
  67. *varptr = argv[*ip + 1];
  68. argv[++(*ip)] = NULL;
  69. }
  70. }
  71. #define GET_SHORT_OPTION_VARIABLE(c, varptr) \
  72. get_short_option_variable(c, varptr, arg, argc, argv, &i)
  73. int main(int argc, char* argv[])
  74. {
  75. bool flag_const = false;
  76. bool flag_extern_c = false;
  77. bool flag_extern = false;
  78. bool flag_forward = false;
  79. bool flag_guard = false;
  80. bool flag_headers = false;
  81. bool flag_raw = false;
  82. bool flag_static = false;
  83. bool flag_volatile = false;
  84. const char* guard = NULL;
  85. const char* identifier = NULL;
  86. const char* includes = NULL;
  87. const char* output = NULL;
  88. const char* type = NULL;
  89. for ( int i = 1; i < argc; i++ )
  90. {
  91. const char* arg = argv[i];
  92. if ( arg[0] != '-' || !arg[1] )
  93. continue;
  94. argv[i] = NULL;
  95. if ( !strcmp(arg, "--") )
  96. break;
  97. if ( arg[1] != '-' )
  98. {
  99. char c;
  100. while ( (c = *++arg) ) switch ( c )
  101. {
  102. case 'c': flag_const = true; break;
  103. case 'e': flag_extern = true; break;
  104. case 'E': flag_extern_c = true; break;
  105. case 'f': flag_forward = true; break;
  106. case 'g': flag_guard = true; break;
  107. case 'G': GET_SHORT_OPTION_VARIABLE('G', &guard); arg = "G"; flag_guard = true; break;
  108. case 'H': flag_headers = true; break;
  109. // TODO: After releasing Sortix 1.1, change -i to --identifier
  110. // rather than -H (--headers).
  111. #if 0 // Future behavior:
  112. case 'i': GET_SHORT_OPTION_VARIABLE('i', &identifier); arg = "i"; break;
  113. #else // Compatibility:
  114. case 'i': flag_headers = true; break;
  115. #endif
  116. case 'o': GET_SHORT_OPTION_VARIABLE('o', &output); arg = "o"; break;
  117. case 'r': flag_raw = true; break;
  118. case 's': flag_static = true; break;
  119. case 't': GET_SHORT_OPTION_VARIABLE('t', &type); arg = "t"; break;
  120. case 'v': flag_volatile = true; break;
  121. default:
  122. errx(1, "unknown option -- '%c'", c);
  123. }
  124. }
  125. else if ( !strcmp(arg, "--const") )
  126. flag_const = true;
  127. else if ( !strcmp(arg, "--extern") )
  128. flag_extern = true;
  129. else if ( !strcmp(arg, "--extern-c") )
  130. flag_extern_c = true;
  131. else if ( !strcmp(arg, "--forward") )
  132. flag_forward = true;
  133. else if ( !strcmp(arg, "--use-guard") )
  134. flag_guard = true;
  135. else if ( !strcmp(arg, "--headers") )
  136. flag_headers = true;
  137. // TODO: After releasing Sortix 1.1, remove --include.
  138. #if 1 // Compatibility:
  139. else if ( !strcmp(arg, "--include") )
  140. flag_headers = true;
  141. #endif
  142. else if ( !strcmp(arg, "--raw") )
  143. flag_raw = true;
  144. else if ( !strcmp(arg, "--static") )
  145. flag_static = true;
  146. else if ( !strcmp(arg, "--volatile") )
  147. flag_volatile = true;
  148. else if ( !strcmp(arg, "--char") )
  149. type = "char";
  150. else if ( !strcmp(arg, "--signed-char") )
  151. type = "signed char";
  152. else if ( !strcmp(arg, "--unsigned-char") )
  153. type = "unsigned char";
  154. else if ( !strcmp(arg, "--int8_t") )
  155. type = "int8_t";
  156. else if ( !strcmp(arg, "--uint8_t") )
  157. type = "uint8_t";
  158. else if ( GET_OPTION_VARIABLE("--guard", &guard) )
  159. flag_guard = true;
  160. else if ( GET_OPTION_VARIABLE("--identifier", &identifier) ) { }
  161. else if ( GET_OPTION_VARIABLE("--includes", &includes) )
  162. flag_headers = true;
  163. else if ( GET_OPTION_VARIABLE("--output", &output) ) { }
  164. else if ( GET_OPTION_VARIABLE("--type", &type) ) { }
  165. else
  166. errx(1, "unknown option: %s", arg);
  167. }
  168. compact_arguments(&argc, &argv);
  169. if ( flag_extern && flag_static )
  170. errx(1, "the --extern and --static options are mutually incompatible");
  171. if ( flag_forward && flag_raw )
  172. errx(1, "the --forward and --raw options are mutually incompatible");
  173. if ( !type )
  174. type = "unsigned char";
  175. if ( !guard )
  176. {
  177. char* new_guard;
  178. if ( output )
  179. new_guard = strdup(output);
  180. else if ( 2 <= argc && strcmp(argv[1], "-") != 0 )
  181. {
  182. if ( asprintf(&new_guard, "%s_H", argv[1]) < 0 )
  183. err(1, "asprintf");
  184. }
  185. else
  186. new_guard = strdup("CARRAY_H");
  187. if ( !new_guard )
  188. err(1, "strdup");
  189. for ( size_t i = 0; new_guard[i]; i++ )
  190. {
  191. if ( 'A' <= new_guard[i] && new_guard[i] <= 'Z' )
  192. continue;
  193. else if ( 'a' <= new_guard[i] && new_guard[i] <= 'z' )
  194. new_guard[i] = 'A' + new_guard[i] - 'a';
  195. else if ( i != 0 && '0' <= new_guard[i] && new_guard[i] <= '9' )
  196. continue;
  197. else if ( new_guard[i] == '+' )
  198. new_guard[i] = 'X';
  199. else if ( i == 0 )
  200. new_guard[i] = 'X';
  201. else
  202. new_guard[i] = '_';
  203. }
  204. guard = new_guard;
  205. }
  206. if ( flag_headers && !includes )
  207. {
  208. if ( !strcmp(type, "int8_t") ||
  209. !strcmp(type, "uint8_t") )
  210. includes = "#include <stdint.h>";
  211. }
  212. if ( !identifier )
  213. {
  214. char* new_identifier;
  215. if ( output )
  216. new_identifier = strdup(output);
  217. else if ( 2 <= argc && strcmp(argv[1], "-") != 0 )
  218. new_identifier = strdup(argv[1]);
  219. else
  220. new_identifier = strdup("carray");
  221. if ( !new_identifier )
  222. err(1, "strdup");
  223. for ( size_t i = 0; new_identifier[i]; i++ )
  224. {
  225. if ( i && new_identifier[i] == '.' && !strchr(new_identifier + i, '/') )
  226. new_identifier[i] = '\0';
  227. else if ( 'a' <= new_identifier[i] && new_identifier[i] <= 'z' )
  228. continue;
  229. else if ( 'A' <= new_identifier[i] && new_identifier[i] <= 'Z' )
  230. new_identifier[i] = 'a' + new_identifier[i] - 'A';
  231. else if ( i != 0 && '0' <= new_identifier[i] && new_identifier[i] <= '9' )
  232. continue;
  233. else if ( guard[i] == '+' )
  234. new_identifier[i] = 'x';
  235. else if ( i == 0 )
  236. new_identifier[i] = 'x';
  237. else
  238. new_identifier[i] = '_';
  239. }
  240. identifier = new_identifier;
  241. }
  242. if ( output && !freopen(output, "w", stdout) )
  243. err(1, "%s", output);
  244. if ( flag_guard && guard )
  245. {
  246. printf("#ifndef %s\n", guard);
  247. printf("#define %s\n", guard);
  248. printf("\n");
  249. }
  250. if ( flag_headers && includes )
  251. {
  252. printf("%s\n", includes);
  253. printf("\n");
  254. }
  255. if ( !flag_raw )
  256. {
  257. if ( flag_extern_c )
  258. {
  259. printf("#if defined(__cplusplus)\n");
  260. printf("extern \"C\" {\n");
  261. printf("#endif\n");
  262. printf("\n");
  263. }
  264. if ( flag_extern )
  265. printf("extern ");
  266. if ( flag_static )
  267. printf("static ");
  268. if ( flag_const )
  269. printf("const ");
  270. if ( flag_volatile )
  271. printf("volatile ");
  272. printf("%s %s[]", type, identifier);
  273. if ( flag_forward )
  274. printf(";\n");
  275. else
  276. printf(" = {\n");
  277. }
  278. if ( !flag_forward )
  279. {
  280. bool begun_row = false;
  281. unsigned int position = 0;
  282. for ( int i = 0; i < argc; i++ )
  283. {
  284. if ( i == 0 && 2 <= argc )
  285. continue;
  286. FILE* fp;
  287. const char* arg;
  288. if ( argc == 1 || !strcmp(argv[i], "-") )
  289. {
  290. arg = "<stdin>";
  291. fp = stdin;
  292. }
  293. else
  294. {
  295. arg = argv[i];
  296. fp = fopen(arg, "r");
  297. }
  298. if ( !fp )
  299. err(1, "%s", arg);
  300. int ic;
  301. while ( (ic = fgetc(fp)) != EOF )
  302. {
  303. printf("%c0x%02X,", position++ ? ' ' : '\t', ic);
  304. begun_row = true;
  305. if ( position == (80 - 8) / 6 )
  306. {
  307. printf("\n");
  308. position = 0;
  309. begun_row = false;
  310. }
  311. }
  312. if ( ferror(fp) )
  313. err(1, "fgetc: %s", arg);
  314. if ( fp != stdin )
  315. fclose(fp);
  316. }
  317. if ( begun_row )
  318. printf("\n");
  319. }
  320. if ( !flag_raw )
  321. {
  322. if ( !flag_forward )
  323. printf("};\n");
  324. if ( flag_extern_c )
  325. {
  326. printf("\n");
  327. printf("#if defined(__cplusplus)\n");
  328. printf("} /* extern \"C\" */\n");
  329. printf("#endif\n");
  330. }
  331. }
  332. if ( flag_guard && guard )
  333. {
  334. printf("\n");
  335. printf("#endif\n");
  336. }
  337. if ( ferror(stdout) || fflush(stdout) == EOF )
  338. err(1, "%s", output ? output : "stdout");
  339. return 0;
  340. }