]> git.draconx.ca Git - cdecl99.git/blob - src/commands.c
Improve cdecl99 error output.
[cdecl99.git] / src / commands.c
1 /*
2  * Main command implementation routines for cdecl99.
3  * Copyright © 2011-2012, 2020-2021 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 /*
27  * Format a declaration according to the given function and return a pointer
28  * to the formatted string.  The returned pointer remains valid until the
29  * next call, after which it must not be re-used.
30  *
31  * Returns NULL on failure.
32  */
33 static const char *
34 do_format(size_t func(char *, size_t, struct cdecl *), struct cdecl *decl)
35 {
36         static size_t bufsz;
37         static char *buf;
38
39         size_t rc;
40
41 retry:
42         rc = func(buf, bufsz, decl);
43         if (rc >= bufsz) {
44                 char *tmp;
45
46                 tmp = realloc(buf, rc + 1);
47                 if (!tmp) {
48                         print_error("%s", _("failed to allocate memory)"));
49                         return NULL;
50                 }
51
52                 buf = tmp;
53                 bufsz = rc + 1;
54                 goto retry;
55         }
56
57         return buf;
58 }
59
60 int run_command_explain(const char *arg)
61 {
62         const struct cdecl_error *err;
63         struct cdecl *decl;
64         const char *str;
65         int ret = -1;
66
67         decl = cdecl_parse_decl(arg);
68         if (!decl) {
69                 err = cdecl_get_error();
70                 print_error("%s", err->str);
71                 goto out;
72         }
73
74         for (struct cdecl *i = decl; i; i = i->next) {
75                 str = do_format(cdecl_explain, i);
76                 if (!str)
77                         goto out;
78
79                 printf("%s\n", str);
80         }
81
82         ret = 0;
83 out:
84         cdecl_free(decl);
85         return ret;
86 }
87
88 int run_command_simplify(const char *arg)
89 {
90         const struct cdecl_error *err;
91         struct cdecl *decl;
92         const char *str;
93         int ret = -1;
94
95         decl = cdecl_parse_decl(arg);
96         if (!decl) {
97                 err = cdecl_get_error();
98                 fprintf(stderr, "%s\n", err->str);
99                 goto out;
100         }
101
102         for (struct cdecl *i = decl; i; i = i->next) {
103                 struct cdecl_declspec *s = i->specifiers;
104
105                 if (i != decl) {
106                         i->specifiers = NULL;
107                         printf(", ");
108                 }
109
110                 str = do_format(cdecl_declare, i);
111                 i->specifiers = s;
112
113                 if (!str)
114                         goto out;
115
116                 printf("%s", str);
117         }
118
119         putchar('\n');
120
121         ret = 0;
122 out:
123         cdecl_free(decl);
124         return ret;
125 }
126
127 int run_command_declare(const char *cmd)
128 {
129         const struct cdecl_error *err;
130         struct cdecl *decl;
131         const char *str;
132         int ret = -1;
133
134         /* The name of the command is significant here. */
135         decl = cdecl_parse_english(cmd);
136         if (!decl) {
137                 err = cdecl_get_error();
138                 fprintf(stderr, "%s\n", err->str);
139                 goto out;
140         }
141
142         /*
143          * English parses have at most one full declarator, so no loop is
144          * needed here.
145          */
146         str = do_format(cdecl_declare, decl);
147         if (!str)
148                 goto out;
149
150         printf("%s\n", str);
151         ret = 0;
152 out:
153         cdecl_free(decl);
154         return ret;
155 }