1/*
2 * Imported NASM preprocessor - glue code
3 *
4 *  Copyright (C) 2002-2007  Peter Johnson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27#include <util.h>
28
29#include <libyasm.h>
30
31#include "nasm.h"
32#include "nasmlib.h"
33#include "nasm-pp.h"
34#include "nasm-eval.h"
35
36typedef struct yasm_preproc_nasm {
37    yasm_preproc_base preproc;   /* Base structure */
38
39    FILE *in;
40    char *line;
41    char *file_name;
42    long prior_linnum;
43    int lineinc;
44} yasm_preproc_nasm;
45yasm_symtab *nasm_symtab;
46static yasm_linemap *cur_lm;
47static yasm_errwarns *cur_errwarns;
48int tasm_compatible_mode = 0;
49int tasm_locals;
50const char *tasm_segment;
51
52#include "nasm-version.c"
53
54typedef struct preproc_dep {
55    STAILQ_ENTRY(preproc_dep) link;
56    char *name;
57} preproc_dep;
58
59static STAILQ_HEAD(preproc_dep_head, preproc_dep) *preproc_deps;
60static int done_dep_preproc;
61
62yasm_preproc_module yasm_nasm_LTX_preproc;
63
64static void
65nil_listgen_init(char *p, efunc e)
66{
67}
68
69static void
70nil_listgen_cleanup(void)
71{
72}
73
74static void
75nil_listgen_output(long v, const void *d, unsigned long v2)
76{
77}
78
79static void
80nil_listgen_line(int v, char *p)
81{
82}
83
84static void
85nil_listgen_uplevel(int v)
86{
87}
88
89static void
90nil_listgen_downlevel(int v)
91{
92}
93
94static ListGen nil_list = {
95    nil_listgen_init,
96    nil_listgen_cleanup,
97    nil_listgen_output,
98    nil_listgen_line,
99    nil_listgen_uplevel,
100    nil_listgen_downlevel
101};
102
103
104static void
105nasm_efunc(int severity, const char *fmt, ...)
106{
107    va_list va;
108
109    va_start(va, fmt);
110    switch (severity & ERR_MASK) {
111        case ERR_WARNING:
112            yasm_warn_set_va(YASM_WARN_PREPROC, fmt, va);
113            break;
114        case ERR_NONFATAL:
115            yasm_error_set_va(YASM_ERROR_GENERAL, fmt, va);
116            break;
117        case ERR_FATAL:
118            yasm_fatal(fmt, va);
119            /*@notreached@*/
120            break;
121        case ERR_PANIC:
122            yasm_internal_error(fmt);   /* FIXME */
123            break;
124        case ERR_DEBUG:
125            break;
126    }
127    va_end(va);
128    yasm_errwarn_propagate(cur_errwarns,
129        yasm_linemap_poke(cur_lm, nasm_src_get_fname(),
130                          (unsigned long)nasm_src_get_linnum()));
131}
132
133static yasm_preproc *
134nasm_preproc_create(const char *in_filename, yasm_symtab *symtab,
135                    yasm_linemap *lm, yasm_errwarns *errwarns)
136{
137    FILE *f;
138    yasm_preproc_nasm *preproc_nasm = yasm_xmalloc(sizeof(yasm_preproc_nasm));
139
140    preproc_nasm->preproc.module = &yasm_nasm_LTX_preproc;
141
142    if (strcmp(in_filename, "-") != 0) {
143        f = fopen(in_filename, "r");
144        if (!f)
145            yasm__fatal( N_("Could not open input file") );
146    }
147    else
148        f = stdin;
149
150    preproc_nasm->in = f;
151    nasm_symtab = symtab;
152    cur_lm = lm;
153    cur_errwarns = errwarns;
154    preproc_deps = NULL;
155    done_dep_preproc = 0;
156    preproc_nasm->line = NULL;
157    preproc_nasm->file_name = NULL;
158    preproc_nasm->prior_linnum = 0;
159    preproc_nasm->lineinc = 0;
160    nasmpp.reset(f, in_filename, 2, nasm_efunc, nasm_evaluate, &nil_list);
161
162    pp_extra_stdmac(nasm_version_mac);
163
164    return (yasm_preproc *)preproc_nasm;
165}
166
167static void
168nasm_preproc_destroy(yasm_preproc *preproc)
169{
170    yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc;
171    nasmpp.cleanup(0);
172    if (preproc_nasm->line)
173        yasm_xfree(preproc_nasm->line);
174    if (preproc_nasm->file_name)
175        yasm_xfree(preproc_nasm->file_name);
176    yasm_xfree(preproc);
177    if (preproc_deps)
178        yasm_xfree(preproc_deps);
179}
180
181static char *
182nasm_preproc_get_line(yasm_preproc *preproc)
183{
184    yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc;
185    long linnum;
186    int altline;
187    char *line;
188
189    if (preproc_nasm->line) {
190        char *retval = preproc_nasm->line;
191        preproc_nasm->line = NULL;
192        return retval;
193    }
194
195    line = nasmpp.getline();
196    if (!line)
197    {
198        nasmpp.cleanup(1);
199        return NULL;    /* EOF */
200    }
201
202    linnum = preproc_nasm->prior_linnum += preproc_nasm->lineinc;
203    altline = nasm_src_get(&linnum, &preproc_nasm->file_name);
204    if (altline != 0) {
205        preproc_nasm->lineinc =
206            (altline != -1 || preproc_nasm->lineinc != 1);
207        preproc_nasm->line = line;
208        line = yasm_xmalloc(40+strlen(preproc_nasm->file_name));
209        sprintf(line, "%%line %ld+%d %s", linnum,
210                preproc_nasm->lineinc, preproc_nasm->file_name);
211        preproc_nasm->prior_linnum = linnum;
212    }
213
214    return line;
215}
216
217void
218nasm_preproc_add_dep(char *name)
219{
220    preproc_dep *dep;
221
222    /* If not processing dependencies, simply return */
223    if (!preproc_deps)
224        return;
225
226    /* Save in preproc_deps */
227    dep = yasm_xmalloc(sizeof(preproc_dep));
228    dep->name = yasm__xstrdup(name);
229    STAILQ_INSERT_TAIL(preproc_deps, dep, link);
230}
231
232static size_t
233nasm_preproc_get_included_file(yasm_preproc *preproc, /*@out@*/ char *buf,
234                               size_t max_size)
235{
236    if (!preproc_deps) {
237        preproc_deps = yasm_xmalloc(sizeof(struct preproc_dep_head));
238        STAILQ_INIT(preproc_deps);
239    }
240
241    for (;;) {
242        char *line;
243
244        /* Pull first dep out of preproc_deps and return it if there is one */
245        if (!STAILQ_EMPTY(preproc_deps)) {
246            char *name;
247            preproc_dep *dep = STAILQ_FIRST(preproc_deps);
248            STAILQ_REMOVE_HEAD(preproc_deps, link);
249            name = dep->name;
250            yasm_xfree(dep);
251            strncpy(buf, name, max_size);
252            buf[max_size-1] = '\0';
253            yasm_xfree(name);
254            return strlen(buf);
255        }
256
257        /* No more preprocessing to do */
258        if (done_dep_preproc) {
259            return 0;
260        }
261
262        /* Preprocess some more, throwing away the result */
263        line = nasmpp.getline();
264        if (line)
265            yasm_xfree(line);
266        else
267            done_dep_preproc = 1;
268    }
269}
270
271static void
272nasm_preproc_add_include_file(yasm_preproc *preproc, const char *filename)
273{
274    pp_pre_include(filename);
275}
276
277static void
278nasm_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval)
279{
280    char *mnv = yasm__xstrdup(macronameval);
281    pp_pre_define(mnv);
282    yasm_xfree(mnv);
283}
284
285static void
286nasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname)
287{
288    char *mn = yasm__xstrdup(macroname);
289    pp_pre_undefine(mn);
290    yasm_xfree(mn);
291}
292
293static void
294nasm_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval)
295{
296    char *mnv = yasm__xstrdup(macronameval);
297    pp_builtin_define(mnv);
298    yasm_xfree(mnv);
299}
300
301static void
302nasm_preproc_add_standard(yasm_preproc *preproc, const char **macros)
303{
304    pp_extra_stdmac(macros);
305}
306
307/* Define preproc structure -- see preproc.h for details */
308yasm_preproc_module yasm_nasm_LTX_preproc = {
309    "Real NASM Preprocessor",
310    "nasm",
311    nasm_preproc_create,
312    nasm_preproc_destroy,
313    nasm_preproc_get_line,
314    nasm_preproc_get_included_file,
315    nasm_preproc_add_include_file,
316    nasm_preproc_predefine_macro,
317    nasm_preproc_undefine_macro,
318    nasm_preproc_define_builtin,
319    nasm_preproc_add_standard
320};
321
322static yasm_preproc *
323tasm_preproc_create(const char *in_filename, yasm_symtab *symtab,
324                    yasm_linemap *lm, yasm_errwarns *errwarns)
325{
326    tasm_compatible_mode = 1;
327    return nasm_preproc_create(in_filename, symtab, lm, errwarns);
328}
329
330yasm_preproc_module yasm_tasm_LTX_preproc = {
331    "Real TASM Preprocessor",
332    "tasm",
333    tasm_preproc_create,
334    nasm_preproc_destroy,
335    nasm_preproc_get_line,
336    nasm_preproc_get_included_file,
337    nasm_preproc_add_include_file,
338    nasm_preproc_predefine_macro,
339    nasm_preproc_undefine_macro,
340    nasm_preproc_define_builtin,
341    nasm_preproc_add_standard
342};
343