ADF_open: add fine grained error reporting, dont fail always
[rofl0r-agsutils.git] / agssemble.c
blob5048f42babd6a52a8b8d9d84af60449c1a75d3c2
1 #define _GNU_SOURCE
2 #define __STDC_WANT_LIB_EXT2__ 1
3 #include <stdio.h>
4 #include "Assembler.h"
5 #include "DataFile.h"
6 #include "preproc.h"
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include "version.h"
10 #define ADS ":::AGSsemble " VERSION " by rofl0r:::"
12 static int usage(char *argv0) {
13 fprintf(stderr, ADS "\nusage:\n%s [-E] [-i file.i] [-I includedir] [-D preproc define] file.s [file.o]\n"
14 "pass an ags assembly filename.\n"
15 "-E: invoke built-in C preprocessor 'tinycpp' on the input file before assembling\n"
16 "-I includedir - add include dir for CPP\n"
17 "-D define - add define for CPP\n"
18 "-i file save preprocessor output to file\n"
19 "if optional second filename is ommited, will write into file.o\n", argv0);
20 return 1;
23 static FILE *freopen_r(FILE *f, char **buf, size_t *size) {
24 fflush(f);
25 fclose(f);
26 return fmemopen(*buf, *size, "r");
29 int main(int argc, char** argv) {
30 struct cpp* cpp = cpp_new();
31 char *tmp, *cppoutfn = 0;
32 int flags = 0, c;
33 while ((c = getopt(argc, argv, "Ei:I:D:")) != EOF) switch(c) {
34 case 'E': flags |= 1; break;
35 case 'i': cppoutfn = optarg; break;
36 case 'I': cpp_add_includedir(cpp, optarg); break;
37 case 'D':
38 if((tmp = strchr(optarg, '='))) *tmp = ' ';
39 cpp_add_define(cpp, optarg);
40 break;
41 default: return usage(argv[0]);
43 if(!argv[optind]) return usage(argv[0]);
44 char* file = argv[optind];
45 char out [256], *outn;
46 if(!argv[optind+1]) {
47 size_t l = strlen(file);
48 char *p;
49 snprintf(out, 256, "%s", file);
50 p = strrchr(out, '.');
51 if(!p) p = out + l;
52 *(p++) = '.';
53 *(p++) = 'o';
54 *p = 0;
55 outn = out;
56 } else outn = argv[optind+1];
57 if(!strcmp(outn, file)) {
58 fprintf(stderr, "error: input and output file (%s) identical!\n", file);
59 return 1;
62 FILE *in = fopen(file, "r");
63 if(!in) {
64 fprintf(stderr, "error opening file %s\n", file);
65 return 1;
68 if(flags & 1) {
69 struct FILE_container {
70 FILE *f;
71 char *buf;
72 size_t len;
73 } output = {0};
74 if(!cppoutfn) output.f = open_memstream(&output.buf, &output.len);
75 else output.f = fopen(cppoutfn, "w");
76 fprintf(stdout, "preprocessing %s ...", file);
77 int ret = cpp_run(cpp, in, output.f, file);
78 if(!ret) {
79 fprintf(stdout, "FAIL\n");
80 return 1;
82 fprintf(stdout, "OK\n");
83 fclose(in);
84 if(!cppoutfn) in = freopen_r(output.f, &output.buf, &output.len);
85 else {
86 fclose(output.f);
87 in = fopen(cppoutfn, "r");
90 // cpp_free(cpp); // FIXME this crashes on windows, find out why
92 AS a_b, *a = &a_b;
93 AS_open_stream(a, in);
95 fprintf(stdout, "assembling %s -> %s ... ", file, outn);
96 int ret = AS_assemble(a, outn);
97 AS_close(a);
99 if(!ret) fprintf(stdout, "FAIL\n");
100 else fprintf(stdout, "OK\n");
101 return !ret;