1/*
2 *
3 * Generate module.c from module.in and Makefile.am or Makefile.
4 *
5 *  Copyright (C) 2004-2007  Peter Johnson
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <ctype.h>
32
33#include "compat-queue.h"
34
35#define MAXNAME 128
36#define MAXLINE 1024
37#define MAXMODULES 128
38#define MAXINCLUDES 256
39
40typedef struct include {
41    STAILQ_ENTRY(include) link;
42    char *filename;
43} include;
44
45int
46main(int argc, char *argv[])
47{
48    FILE *in, *out;
49    char *str;
50    int i;
51    size_t len;
52    char *strp;
53    char *modules[MAXMODULES];
54    int num_modules = 0;
55    STAILQ_HEAD(includehead, include) includes =
56        STAILQ_HEAD_INITIALIZER(includes);
57    include *inc;
58    int isam = 0;
59    int linecont = 0;
60    char *outfile;
61
62    if (argc != 4) {
63        fprintf(stderr, "Usage: %s <module.in> <Makefile[.am]> <outfile>\n", argv[0]);
64        return EXIT_FAILURE;
65    }
66
67    outfile = argv[3];
68    str = malloc(MAXLINE);
69
70    /* Starting with initial input Makefile, look for include <file> or
71     * YASM_MODULES += <module>.  Note this currently doesn't handle
72     * a relative starting path.
73     */
74    len = strlen(argv[2]);
75    inc = malloc(sizeof(include));
76    inc->filename = malloc(len+1);
77    strcpy(inc->filename, argv[2]);
78    STAILQ_INSERT_TAIL(&includes, inc, link);
79
80    isam = argv[2][len-2] == 'a' && argv[2][len-1] == 'm';
81
82    while (!STAILQ_EMPTY(&includes)) {
83        inc = STAILQ_FIRST(&includes);
84        STAILQ_REMOVE_HEAD(&includes, link);
85        in = fopen(inc->filename, "rt");
86        if (!in) {
87            fprintf(stderr, "Could not open `%s'.\n", inc->filename);
88            return EXIT_FAILURE;
89        }
90        free(inc->filename);
91        free(inc);
92
93        while (fgets(str, MAXLINE, in)) {
94            /* Strip off any trailing whitespace */
95            len = strlen(str);
96            if (len > 0) {
97                strp = &str[len-1];
98                while (len > 0 && isspace(*strp)) {
99                    *strp-- = '\0';
100                    len--;
101                }
102            }
103
104            strp = str;
105
106            /* Skip whitespace */
107            while (isspace(*strp))
108                strp++;
109
110            /* Skip comments */
111            if (*strp == '#')
112                continue;
113
114            /* If line continuation, skip to continue copy */
115            if (linecont)
116                goto keepgoing;
117
118            /* Check for include if original input is .am file */
119            if (isam && strncmp(strp, "include", 7) == 0 && isspace(strp[7])) {
120                strp += 7;
121                while (isspace(*strp))
122                    strp++;
123                /* Build new include and add to end of list */
124                inc = malloc(sizeof(include));
125                inc->filename = malloc(strlen(strp)+1);
126                strcpy(inc->filename, strp);
127                STAILQ_INSERT_TAIL(&includes, inc, link);
128                continue;
129            }
130
131            /* Check for YASM_MODULES = or += */
132            if (strncmp(strp, "YASM_MODULES", 12) != 0)
133                continue;
134            strp += 12;
135            while (isspace(*strp))
136                strp++;
137            if (strncmp(strp, "+=", 2) != 0 && *strp != '=')
138                continue;
139            if (*strp == '+')
140                strp++;
141            strp++;
142            while (isspace(*strp))
143                strp++;
144
145keepgoing:
146            /* Check for continuation */
147            if (len > 0 && str[len-1] == '\\') {
148                str[len-1] = '\0';
149                while (isspace(*strp))
150                    *strp-- = '\0';
151                linecont = 1;
152            } else
153                linecont = 0;
154
155            while (*strp != '\0') {
156                /* Copy module name */
157                modules[num_modules] = malloc(MAXNAME);
158                len = 0;
159                while (*strp != '\0' && !isspace(*strp))
160                    modules[num_modules][len++] = *strp++;
161                modules[num_modules][len] = '\0';
162                num_modules++;
163
164                while (isspace(*strp))
165                    strp++;
166            }
167        }
168        fclose(in);
169    }
170
171    out = fopen(outfile, "wt");
172
173    if (!out) {
174        fprintf(stderr, "Could not open `%s'.\n", outfile);
175        return EXIT_FAILURE;
176    }
177
178    fprintf(out, "/* This file auto-generated by genmodule.c"
179                 " - don't edit it */\n\n");
180
181    in = fopen(argv[1], "rt");
182    if (!in) {
183        fprintf(stderr, "Could not open `%s'.\n", argv[1]);
184        fclose(out);
185        remove(outfile);
186        return EXIT_FAILURE;
187    }
188
189    len = 0;
190    while (fgets(str, MAXLINE, in)) {
191        if (strncmp(str, "MODULES_", 8) == 0) {
192            len = 0;
193            strp = str+8;
194            while (*strp != '\0' && *strp != '_') {
195                len++;
196                strp++;
197            }
198            *strp = '\0';
199
200            for (i=0; i<num_modules; i++) {
201                if (strncmp(modules[i], str+8, len) == 0) {
202                    fprintf(out, "    {\"%s\", &yasm_%s_LTX_%s},\n",
203                            modules[i]+len+1, modules[i]+len+1, str+8);
204                }
205            }
206        } else if (strncmp(str, "EXTERN_LIST", 11) == 0) {
207            for (i=0; i<num_modules; i++) {
208                strcpy(str, modules[i]);
209                strp = str;
210                while (*strp != '\0' && *strp != '_')
211                    strp++;
212                *strp++ = '\0';
213
214                fprintf(out, "extern yasm_%s_module yasm_%s_LTX_%s;\n",
215                        str, strp, str);
216            }
217        } else
218            fputs(str, out);
219    }
220
221    fclose(in);
222    fclose(out);
223
224    for (i=0; i<num_modules; i++)
225        free(modules[i]);
226    free(str);
227
228    return EXIT_SUCCESS;
229}
230