]> git.draconx.ca Git - cdecl99.git/blob - src/commands.c
cdecl99: Fix some improper error message formatting.
[cdecl99.git] / src / commands.c
1 /*
2  * Main command implementation routines for cdecl99.
3  * Copyright © 2011-2012, 2020-2021, 2023 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                 print_error("%s", cdecl_get_error()->str);
70                 goto out;
71         }
72
73         for (struct cdecl *i = decl; i; i = i->next) {
74                 str = do_format(cdecl_explain, i);
75                 if (!str)
76                         goto out;
77
78                 printf("%s\n", str);
79         }
80
81         ret = 0;
82 out:
83         cdecl_free(decl);
84         return ret;
85 }
86
87 int run_command_simplify(const char *arg)
88 {
89         const struct cdecl_error *err;
90         struct cdecl *decl;
91         const char *str;
92         int ret = -1;
93
94         decl = cdecl_parse_decl(arg);
95         if (!decl) {
96                 print_error("%s", cdecl_get_error()->str);
97                 goto out;
98         }
99
100         for (struct cdecl *i = decl; i; i = i->next) {
101                 struct cdecl_declspec *s = i->specifiers;
102
103                 if (i != decl) {
104                         i->specifiers = NULL;
105                         printf(", ");
106                 }
107
108                 str = do_format(cdecl_declare, i);
109                 i->specifiers = s;
110
111                 if (!str)
112                         goto out;
113
114                 printf("%s", str);
115         }
116
117         putchar('\n');
118
119         ret = 0;
120 out:
121         cdecl_free(decl);
122         return ret;
123 }
124
125 int run_command_declare(const char *cmd)
126 {
127         struct cdecl *decl;
128         const char *str;
129         int ret = -1;
130
131         /* The name of the command is significant here. */
132         decl = cdecl_parse_english(cmd);
133         if (!decl) {
134                 print_error("%s", cdecl_get_error()->str);
135                 goto out;
136         }
137
138         /*
139          * English parses have at most one full declarator, so no loop is
140          * needed here.
141          */
142         str = do_format(cdecl_declare, decl);
143         if (!str)
144                 goto out;
145
146         printf("%s\n", str);
147         ret = 0;
148 out:
149         cdecl_free(decl);
150         return ret;
151 }