]> git.draconx.ca Git - cdecl99.git/blob - src/commands.c
Release 1.3.
[cdecl99.git] / src / commands.c
1 /*
2  * Main command implementation routines for cdecl99.
3  * Copyright © 2011-2012, 2020-2021, 2023-2024 Nick Bowler
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "cdecl99.h"
24 #include "cdecl.h"
25
26 static struct cdecl *do_parse(const char *s, int input_mode)
27 {
28         struct cdecl *parse;
29
30         if (input_mode == INPUT_C)
31                 parse = cdecl_parse_decl(s);
32         else
33                 parse = cdecl_parse_english(s);
34
35         if (!parse)
36                 print_error("%s", cdecl_get_error()->str);
37
38         return parse;
39 }
40
41 /*
42  * Format a declaration according to the given function and return a pointer
43  * to the formatted string.  The returned pointer remains valid until the
44  * next call, after which it must not be re-used.
45  *
46  * Returns NULL on failure.
47  */
48 static const char *do_render(struct cdecl *decl, int output_mode)
49 {
50         static size_t bufsz;
51         static char *buf;
52         size_t rc;
53
54 retry:
55         if (output_mode == OUTPUT_C)
56                 rc = cdecl_declare(buf, bufsz, decl);
57         else
58                 rc = cdecl_explain(buf, bufsz, decl);
59
60         if (rc >= bufsz) {
61                 char *tmp;
62
63                 tmp = realloc(buf, rc + 1);
64                 if (!tmp) {
65                         print_error("%s", _("failed to allocate memory"));
66                         return NULL;
67                 }
68
69                 buf = tmp;
70                 bufsz = rc + 1;
71                 goto retry;
72         }
73
74         return buf;
75 }
76
77 /*
78  * Parse the given string as either C or English (based on input_mode),
79  * then print the result as either C or English (based on output_mode).
80  */
81 int run_command_cdecl(const char *s, int input_mode, int output_mode)
82 {
83         struct cdecl *i, *parse;
84         int ret = -1;
85
86         if (!(parse = do_parse(s, input_mode)))
87                 goto out;
88
89         for (i = parse; i; i = i->next) {
90                 const char *str;
91
92                 if (!(str = do_render(i, output_mode)))
93                         goto out;
94
95                 /*
96                  * In C output, only the first declarator needs specifiers
97                  * printed, and only the last declarator needs a newline.
98                  */
99                 if (output_mode == OUTPUT_C && i->next) {
100                         i->next->specifiers = NULL;
101                         printf("%s, ", str);
102                 } else {
103                         puts(str);
104                 }
105         }
106
107         ret = 0;
108 out:
109         cdecl_free(parse);
110         return ret;
111 }