Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / lint / lpass2 / checkargs.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 /* $Id: checkargs.c,v 1.7 1994/06/24 12:25:28 ceriel Exp $ */
6
7 /******** A R G U M E N T   T Y P E   C H E C K I N G ********/
8
9 #include        "private.h"
10 #include        "inpdef.h"
11
12 extern char *strcpy();
13
14 #define streq(s1,s2)    (strcmp(s1, s2) == 0)
15
16 /* a format is developed into a normal parameter definition */
17 PRIVATE int is_formatargs;              /* present or not */
18 PRIVATE char formatargs[1000];          /* the definitions */
19
20 PRIVATE chk_argtps();
21 PRIVATE char *next_argtype();
22 PRIVATE int type_match();
23 PRIVATE form_type();
24 PRIVATE conv_format();
25
26 int
27 type_equal(act, form)
28         char *act, *form;
29 {
30         return  streq(act, form)
31         ||      streq(act, "erroneous")
32         ||      streq(form, "erroneous");
33 }
34
35 chk_args(id, def)
36         struct inpdef *id, *def;
37 {
38         char *act_tp = id->id_argtps;
39         int nrargs = 0;                 /* number of args */
40
41         /* void is a special case */
42         if (    /* the definition has one void argument */
43                 def->id_nrargs == 1 && streq(def->id_argtps, "void:")
44         &&      /* the referent has no argumants */
45                 id->id_nrargs == 0
46         )       /* we have a prefect match */
47                 return;
48
49         /* clear format */
50         is_formatargs = 0;
51
52         /* check normal arguments */
53         chk_argtps(id, def, &nrargs, act_tp, def->id_argtps);
54
55         if (is_formatargs) {
56                 /* there was a format */
57                 register int i;
58
59                 /* skip over the actuals already covered */
60                 for (i = 0; i < nrargs; i++) {
61                         act_tp = next_argtype(act_tp);
62                 }
63
64                 /* and check the format arguments */
65                 chk_argtps(id, (struct inpdef *)0, &nrargs,
66                                                 act_tp, &formatargs[0]);
67         }
68 }
69
70 PRIVATE chk_argtps(id, def, nrargs, act_tp, form_tp)
71         struct inpdef *id;              /* the actual call */
72         struct inpdef *def;             /* 0 for format-derived definition */
73         int *nrargs;                    /* in-out parameter, counting */
74         char *act_tp;                   /* actual types */
75         char *form_tp;                  /* formal type definitions */
76 {
77         while (*act_tp && *form_tp && *form_tp != '.') {
78                 register char *act_start = act_tp;
79                 register char *form_start = form_tp;
80
81                 /* isolate actual argument type */
82                 act_tp = next_argtype(act_tp);
83                 act_tp[-1] = '\0';
84
85                 /* isolate formal argument type */
86                 form_tp = next_argtype(form_tp);
87                 form_tp[-1] = '\0';
88
89                 (*nrargs)++;
90                 if (!type_match(id, act_start, form_start)) {
91                         char act_form[100];
92                         char form_form[100];
93
94                         form_type(act_form, act_start);
95                         form_type(form_form, form_start);
96                         report("%L: arg %d of %s (%s) differs from that in %L (%s)",
97                                 id, *nrargs, id->id_name,
98                                 act_form, def, form_form);
99                 }
100                 act_tp[-1] = ':';
101                 form_tp[-1] = ':';
102         }
103
104         if (*form_tp == '.')    /* ellipsis */
105                 return;
106
107         if (*form_tp) {
108                 /* formal type definitions not exhausted */
109                 report("%L: %s has fewer arguments than in %L",
110                         id, id->id_name, def);
111         }
112         if (*act_tp) {
113                 /* actual types not exhausted */
114                 if (def && def->id_nrargs < 0) {
115                         /* the function had VARARGS */
116                 }
117                 else {
118                         report("%L: %s has more arguments than in %L",
119                                 id, id->id_name, def);
120                 }
121         }
122 }
123
124 PRIVATE char *
125 next_argtype(tp)
126         char *tp;
127 {
128         while (*tp && *tp != ':') {
129                 tp++;
130         }
131         if (*tp == ':') {
132                 tp++;
133         }
134         return tp;
135 }
136
137 int
138 PRIVATE type_match(id, act, form)
139         struct inpdef *id;
140         char *act, *form;
141 {
142         if (form[0] == '"' && act[0] == '"') {
143                 conv_format(id, act, form);
144                 return 1;
145         }
146
147         if (    (form[0] == '"' && streq(act, "char*"))
148         ||      (act[0] == '"' && streq(form, "char*"))
149         ) {
150                 return 1;
151         }
152
153         if (type_equal(act, form))
154                 return 1;
155
156         if (act[0] == '+') {
157                 /* a non-negative constant */
158                 /* might be signed or unsigned */
159                 if (type_equal(&act[1], form))
160                         return 1;
161                 if (    strncmp(form, "unsigned ", strlen("unsigned ")) == 0
162                 &&      type_equal(&act[1], &form[strlen("unsigned ")])
163                 ) {
164                         return 1;
165                 }
166         }
167         return 0;
168 }
169
170 PRIVATE conv_format(id, act, form)
171         struct inpdef *id;
172         char *act, *form;
173 {
174         /*      convert the actual format into a def-list, using the
175                 formal format (form) as a map to convert from %X to type
176         */
177         register char *fmt = &formatargs[0];
178
179         is_formatargs = 1;
180         while (*act) {
181                 register char *map;
182
183                 /* find next conversion specification */
184                 while (*act && *act != '%') {
185                         act++;
186                 }
187                 if (*act++ != '%')
188                         break;
189                 if (*act == '%') {
190                         /* %% */
191                         act++;
192                         continue;
193                 }
194
195                 /* process options */
196                 if (*act && *act == '-') {
197                         act++;
198                 }
199                 while (*act && ('0' <= *act && *act <= '9')) {
200                         act++;
201                 }
202                 if (*act == '*') {
203                         act++;
204                         strcpy(fmt, "int:");
205                         fmt += 4;
206                 }
207                 if (*act && *act == '.') {
208                         act++;
209                 }
210                 while (*act && ('0' <= *act && *act <= '9')) {
211                         act++;
212                 }
213                 if (*act == '*') {
214                         act++;
215                         strcpy(fmt, "int:");
216                         fmt += 4;
217                 }
218
219                 map = form;
220                 while (*map) {
221                         register char *cs = act;
222
223                         /* find next conversion mapping */
224                         while (*map && *map != '%') {
225                                 map++;
226                         }
227                         if (*map++ != '%') {
228                                 /* we ran off the map */
229                                 report("%L: unknown conversion specification in format",
230                                         id);
231                                 break;
232                         }
233
234                         while (*map && *map != '=') {
235                                 register int match = 0;
236
237                                 if (*map == '[') {
238                                         while (*map && *map != ']') {
239                                                 if (*map == *cs) {
240                                                         match = 1;
241                                                 }
242                                                 map++;
243                                         }
244                                 }
245                                 else {
246                                         match = (*map == *cs);
247                                 }
248
249                                 if (match) {
250                                         map++, cs++;
251                                 }
252                                 else    break;
253                         }
254                         if (*map++ == '=') {
255                                 /* found the type belonging to %*cs */
256                                 while (*map && *map != '%' && *map != '"') {
257                                         *fmt++ = *map++;
258                                 }
259                                 *fmt++ = ':';
260                                 act = cs;
261                                 break;
262                         }
263                 }
264         }
265         *fmt++ = '\0';
266 }
267
268 PRIVATE form_type(buff, tp)
269         char buff[];
270         char *tp;
271 {       /*      store a formatted version of tp in buff
272         */
273         if (tp[0] == '"') {
274                 strcpy(buff, "char*");
275         }
276         else if (tp[0] == '+') {
277                 sprintf(buff, "[unsigned] %s", &tp[1]);
278         }
279         else {
280                 strcpy(buff, tp);
281         }
282 }
283