[Patch][binutils][arm] .bfloat16 directive for Arm [6/X]
[deliverable/binutils-gdb.git] / gas / macro.c
CommitLineData
fea17916 1/* macro.c - macro support for gas
82704155 2 Copyright (C) 1994-2019 Free Software Foundation, Inc.
252b5132
RH
3
4 Written by Steve and Judy Chamberlain of Cygnus Support,
5 sac@cygnus.com
6
7 This file is part of GAS, the GNU Assembler.
8
9 GAS is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
ec2655a6 11 the Free Software Foundation; either version 3, or (at your option)
252b5132
RH
12 any later version.
13
14 GAS is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GAS; see the file COPYING. If not, write to the Free
4b4da160
NC
21 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
252b5132 23
89658e52 24#include "as.h"
3882b010 25#include "safe-ctype.h"
252b5132 26#include "sb.h"
252b5132
RH
27#include "macro.h"
28
252b5132 29/* The routines in this file handle macro definition and expansion.
fea17916 30 They are called by gas. */
252b5132 31
252b5132
RH
32#define ISWHITE(x) ((x) == ' ' || (x) == '\t')
33
34#define ISSEP(x) \
35 ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \
36 || (x) == ')' || (x) == '(' \
37 || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>')))
38
39#define ISBASE(x) \
40 ((x) == 'b' || (x) == 'B' \
41 || (x) == 'q' || (x) == 'Q' \
42 || (x) == 'h' || (x) == 'H' \
43 || (x) == 'd' || (x) == 'D')
44
45/* The macro hash table. */
46
c1d05a60 47struct hash_control *macro_hash;
252b5132
RH
48
49/* Whether any macros have been defined. */
50
51int macro_defined;
52
fea17916 53/* Whether we are in alternate syntax mode. */
252b5132
RH
54
55static int macro_alternate;
56
57/* Whether we are in MRI mode. */
58
59static int macro_mri;
60
61/* Whether we should strip '@' characters. */
62
63static int macro_strip_at;
64
65/* Function to use to parse an expression. */
66
39a45edc 67static size_t (*macro_expr) (const char *, size_t, sb *, offsetT *);
252b5132
RH
68
69/* Number of macro expansions that have been done. */
70
71static int macro_number;
72
73/* Initialize macro processing. */
74
75void
254d758c 76macro_init (int alternate, int mri, int strip_at,
39a45edc 77 size_t (*exp) (const char *, size_t, sb *, offsetT *))
252b5132
RH
78{
79 macro_hash = hash_new ();
80 macro_defined = 0;
81 macro_alternate = alternate;
82 macro_mri = mri;
83 macro_strip_at = strip_at;
91d6fa6a 84 macro_expr = exp;
252b5132
RH
85}
86
caa32fe5
NC
87/* Switch in and out of alternate mode on the fly. */
88
89void
2766e5e4 90macro_set_alternate (int alternate)
caa32fe5
NC
91{
92 macro_alternate = alternate;
93}
94
252b5132
RH
95/* Switch in and out of MRI mode on the fly. */
96
97void
254d758c 98macro_mri_mode (int mri)
252b5132
RH
99{
100 macro_mri = mri;
101}
102
103/* Read input lines till we get to a TO string.
104 Increase nesting depth if we get a FROM string.
105 Put the results into sb at PTR.
ca3bc58f 106 FROM may be NULL (or will be ignored) if TO is "ENDR".
252b5132
RH
107 Add a new input line to an sb using GET_LINE.
108 Return 1 on success, 0 on unexpected EOF. */
109
110int
254d758c 111buffer_and_nest (const char *from, const char *to, sb *ptr,
39a45edc 112 size_t (*get_line) (sb *))
252b5132 113{
39a45edc
AM
114 size_t from_len;
115 size_t to_len = strlen (to);
252b5132 116 int depth = 1;
39a45edc
AM
117 size_t line_start = ptr->len;
118 size_t more = get_line (ptr);
252b5132 119
4ac14836 120 if (to_len == 4 && strcasecmp (to, "ENDR") == 0)
ca3bc58f
JB
121 {
122 from = NULL;
123 from_len = 0;
124 }
125 else
126 from_len = strlen (from);
127
252b5132
RH
128 while (more)
129 {
0e470c55 130 /* Try to find the first pseudo op on the line. */
39a45edc 131 size_t i = line_start;
f19df8f7 132 bfd_boolean had_colon = FALSE;
252b5132 133
0e470c55
AM
134 /* With normal syntax we can suck what we want till we get
135 to the dot. With the alternate, labels have to start in
136 the first column, since we can't tell what's a label and
137 what's a pseudoop. */
252b5132 138
0e470c55
AM
139 if (! LABELS_WITHOUT_COLONS)
140 {
141 /* Skip leading whitespace. */
142 while (i < ptr->len && ISWHITE (ptr->ptr[i]))
143 i++;
144 }
252b5132 145
0e470c55
AM
146 for (;;)
147 {
148 /* Skip over a label, if any. */
149 if (i >= ptr->len || ! is_name_beginner (ptr->ptr[i]))
150 break;
151 i++;
152 while (i < ptr->len && is_part_of_name (ptr->ptr[i]))
153 i++;
154 if (i < ptr->len && is_name_ender (ptr->ptr[i]))
155 i++;
0e470c55
AM
156 /* Skip whitespace. */
157 while (i < ptr->len && ISWHITE (ptr->ptr[i]))
158 i++;
159 /* Check for the colon. */
160 if (i >= ptr->len || ptr->ptr[i] != ':')
5e75c3ab 161 {
f19df8f7
AM
162 /* LABELS_WITHOUT_COLONS doesn't mean we cannot have a
163 colon after a label. If we do have a colon on the
164 first label then handle more than one label on the
165 line, assuming that each label has a colon. */
166 if (LABELS_WITHOUT_COLONS && !had_colon)
167 break;
0e470c55
AM
168 i = line_start;
169 break;
5e75c3ab 170 }
0e470c55
AM
171 i++;
172 line_start = i;
f19df8f7 173 had_colon = TRUE;
252b5132 174 }
0e470c55 175
29f8404c 176 /* Skip trailing whitespace. */
252b5132
RH
177 while (i < ptr->len && ISWHITE (ptr->ptr[i]))
178 i++;
179
180 if (i < ptr->len && (ptr->ptr[i] == '.'
ca3bc58f 181 || NO_PSEUDO_DOT
252b5132
RH
182 || macro_mri))
183 {
ca3bc58f 184 if (! flag_m68k_mri && ptr->ptr[i] == '.')
29f8404c 185 i++;
ca3bc58f
JB
186 if (from == NULL
187 && strncasecmp (ptr->ptr + i, "IRPC", from_len = 4) != 0
188 && strncasecmp (ptr->ptr + i, "IRP", from_len = 3) != 0
189 && strncasecmp (ptr->ptr + i, "IREPC", from_len = 5) != 0
190 && strncasecmp (ptr->ptr + i, "IREP", from_len = 4) != 0
191 && strncasecmp (ptr->ptr + i, "REPT", from_len = 4) != 0
192 && strncasecmp (ptr->ptr + i, "REP", from_len = 3) != 0)
193 from_len = 0;
194 if ((from != NULL
195 ? strncasecmp (ptr->ptr + i, from, from_len) == 0
196 : from_len > 0)
29f8404c 197 && (ptr->len == (i + from_len)
5e75c3ab
JB
198 || ! (is_part_of_name (ptr->ptr[i + from_len])
199 || is_name_ender (ptr->ptr[i + from_len]))))
252b5132 200 depth++;
c1eae114 201 if (strncasecmp (ptr->ptr + i, to, to_len) == 0
29f8404c 202 && (ptr->len == (i + to_len)
5e75c3ab
JB
203 || ! (is_part_of_name (ptr->ptr[i + to_len])
204 || is_name_ender (ptr->ptr[i + to_len]))))
252b5132
RH
205 {
206 depth--;
207 if (depth == 0)
208 {
29f8404c 209 /* Reset the string to not include the ending rune. */
252b5132
RH
210 ptr->len = line_start;
211 break;
212 }
213 }
6d1ace68
CM
214
215 /* PR gas/16908
216 Apply and discard .linefile directives that appear within
217 the macro. For long macros, one might want to report the
218 line number information associated with the lines within
219 the macro definition, but we would need more infrastructure
220 to make that happen correctly (e.g. resetting the line
221 number when expanding the macro), and since for short
222 macros we clearly prefer reporting the point of expansion
223 anyway, there's not an obviously better fix here. */
224 if (strncasecmp (ptr->ptr + i, "linefile", 8) == 0)
225 {
6d1ace68
CM
226 char saved_eol_char = ptr->ptr[ptr->len];
227
228 ptr->ptr[ptr->len] = '\0';
af60449c 229 temp_ilp (ptr->ptr + i + 8);
6d1ace68 230 s_app_line (0);
af60449c 231 restore_ilp ();
6d1ace68 232 ptr->ptr[ptr->len] = saved_eol_char;
6d1ace68
CM
233 ptr->len = line_start;
234 }
252b5132
RH
235 }
236
0822d075
NC
237 /* Add the original end-of-line char to the end and keep running. */
238 sb_add_char (ptr, more);
252b5132
RH
239 line_start = ptr->len;
240 more = get_line (ptr);
241 }
242
243 /* Return 1 on success, 0 on unexpected EOF. */
244 return depth == 0;
245}
246
247/* Pick up a token. */
248
39a45edc
AM
249static size_t
250get_token (size_t idx, sb *in, sb *name)
252b5132
RH
251{
252 if (idx < in->len
5e75c3ab 253 && is_name_beginner (in->ptr[idx]))
252b5132
RH
254 {
255 sb_add_char (name, in->ptr[idx++]);
256 while (idx < in->len
5e75c3ab
JB
257 && is_part_of_name (in->ptr[idx]))
258 {
259 sb_add_char (name, in->ptr[idx++]);
260 }
261 if (idx < in->len
262 && is_name_ender (in->ptr[idx]))
252b5132
RH
263 {
264 sb_add_char (name, in->ptr[idx++]);
265 }
266 }
29f8404c 267 /* Ignore trailing &. */
252b5132
RH
268 if (macro_alternate && idx < in->len && in->ptr[idx] == '&')
269 idx++;
270 return idx;
271}
272
273/* Pick up a string. */
274
39a45edc
AM
275static size_t
276getstring (size_t idx, sb *in, sb *acc)
252b5132 277{
252b5132 278 while (idx < in->len
29f8404c 279 && (in->ptr[idx] == '"'
252b5132
RH
280 || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
281 || (in->ptr[idx] == '\'' && macro_alternate)))
282 {
2f6178c1 283 if (in->ptr[idx] == '<')
252b5132
RH
284 {
285 int nest = 0;
286 idx++;
10c172ba
WH
287 while (idx < in->len
288 && (in->ptr[idx] != '>' || nest))
252b5132
RH
289 {
290 if (in->ptr[idx] == '!')
291 {
29f8404c 292 idx++;
252b5132
RH
293 sb_add_char (acc, in->ptr[idx++]);
294 }
295 else
296 {
0e31b3e1 297 if (in->ptr[idx] == '>')
252b5132 298 nest--;
0e31b3e1 299 if (in->ptr[idx] == '<')
252b5132
RH
300 nest++;
301 sb_add_char (acc, in->ptr[idx++]);
302 }
303 }
304 idx++;
305 }
306 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
307 {
308 char tchar = in->ptr[idx];
c06ae4f2 309 int escaped = 0;
29f8404c 310
252b5132 311 idx++;
29f8404c 312
252b5132
RH
313 while (idx < in->len)
314 {
29f8404c 315 if (in->ptr[idx - 1] == '\\')
c06ae4f2
UC
316 escaped ^= 1;
317 else
318 escaped = 0;
319
252b5132
RH
320 if (macro_alternate && in->ptr[idx] == '!')
321 {
e972090a 322 idx ++;
29f8404c 323
1994a7c7
NC
324 sb_add_char (acc, in->ptr[idx]);
325
e972090a 326 idx ++;
252b5132 327 }
c06ae4f2
UC
328 else if (escaped && in->ptr[idx] == tchar)
329 {
330 sb_add_char (acc, tchar);
e972090a 331 idx ++;
c06ae4f2 332 }
252b5132
RH
333 else
334 {
335 if (in->ptr[idx] == tchar)
336 {
e972090a 337 idx ++;
29f8404c 338
252b5132
RH
339 if (idx >= in->len || in->ptr[idx] != tchar)
340 break;
341 }
29f8404c 342
252b5132 343 sb_add_char (acc, in->ptr[idx]);
e972090a 344 idx ++;
252b5132
RH
345 }
346 }
347 }
348 }
29f8404c 349
252b5132
RH
350 return idx;
351}
352
353/* Fetch string from the input stream,
354 rules:
355 'Bxyx<whitespace> -> return 'Bxyza
df40eaf9
NC
356 %<expr> -> return string of decimal value of <expr>
357 "string" -> return string
2f6178c1 358 (string) -> return (string-including-whitespaces)
df40eaf9 359 xyx<whitespace> -> return xyz. */
252b5132 360
39a45edc
AM
361static size_t
362get_any_string (size_t idx, sb *in, sb *out)
252b5132
RH
363{
364 sb_reset (out);
365 idx = sb_skip_white (idx, in);
366
367 if (idx < in->len)
368 {
9df59bba 369 if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
252b5132 370 {
1b2ed39c 371 while (idx < in->len && !ISSEP (in->ptr[idx]))
252b5132
RH
372 sb_add_char (out, in->ptr[idx++]);
373 }
be03cc84 374 else if (in->ptr[idx] == '%' && macro_alternate)
252b5132 375 {
39a45edc 376 offsetT val;
3076e594 377 char buf[64];
df40eaf9 378
29f8404c 379 /* Turns the next expression into a string. */
06f030db 380 /* xgettext: no-c-format */
252b5132
RH
381 idx = (*macro_expr) (_("% operator needs absolute expression"),
382 idx + 1,
383 in,
384 &val);
39a45edc 385 sprintf (buf, "%" BFD_VMA_FMT "d", val);
252b5132
RH
386 sb_add_string (out, buf);
387 }
388 else if (in->ptr[idx] == '"'
389 || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
390 || (macro_alternate && in->ptr[idx] == '\''))
391 {
9f6f925e 392 if (macro_alternate && ! macro_strip_at && in->ptr[idx] != '<')
252b5132 393 {
29f8404c 394 /* Keep the quotes. */
9f6f925e 395 sb_add_char (out, '"');
252b5132 396 idx = getstring (idx, in, out);
9f6f925e 397 sb_add_char (out, '"');
252b5132
RH
398 }
399 else
400 {
401 idx = getstring (idx, in, out);
402 }
403 }
29f8404c 404 else
252b5132 405 {
add39d23 406 char *br_buf = XNEWVEC (char, 1);
0e31b3e1
JB
407 char *in_br = br_buf;
408
409 *in_br = '\0';
29f8404c 410 while (idx < in->len
0e31b3e1
JB
411 && (*in_br
412 || (in->ptr[idx] != ' '
413 && in->ptr[idx] != '\t'))
be03cc84
JB
414 && in->ptr[idx] != ','
415 && (in->ptr[idx] != '<'
416 || (! macro_alternate && ! macro_mri)))
252b5132 417 {
0e31b3e1 418 char tchar = in->ptr[idx];
df40eaf9 419
0e31b3e1
JB
420 switch (tchar)
421 {
422 case '"':
423 case '\'':
252b5132
RH
424 sb_add_char (out, in->ptr[idx++]);
425 while (idx < in->len
426 && in->ptr[idx] != tchar)
29f8404c 427 sb_add_char (out, in->ptr[idx++]);
252b5132 428 if (idx == in->len)
4ac14836
NC
429 {
430 free (br_buf);
431 return idx;
432 }
0e31b3e1
JB
433 break;
434 case '(':
435 case '[':
436 if (in_br > br_buf)
437 --in_br;
438 else
439 {
add39d23 440 br_buf = XNEWVEC (char, strlen (in_br) + 2);
4ac14836
NC
441 strcpy (br_buf + 1, in_br);
442 free (in_br);
0e31b3e1
JB
443 in_br = br_buf;
444 }
445 *in_br = tchar;
446 break;
447 case ')':
448 if (*in_br == '(')
449 ++in_br;
450 break;
451 case ']':
452 if (*in_br == '[')
453 ++in_br;
454 break;
252b5132 455 }
0e31b3e1
JB
456 sb_add_char (out, tchar);
457 ++idx;
252b5132 458 }
4ac14836 459 free (br_buf);
252b5132
RH
460 }
461 }
462
463 return idx;
464}
465
6eaeac8a
JB
466/* Allocate a new formal. */
467
468static formal_entry *
469new_formal (void)
470{
471 formal_entry *formal;
472
325801bd 473 formal = XNEW (formal_entry);
6eaeac8a
JB
474
475 sb_new (&formal->name);
476 sb_new (&formal->def);
477 sb_new (&formal->actual);
478 formal->next = NULL;
479 formal->type = FORMAL_OPTIONAL;
480 return formal;
481}
482
483/* Free a formal. */
484
485static void
486del_formal (formal_entry *formal)
487{
488 sb_kill (&formal->actual);
489 sb_kill (&formal->def);
490 sb_kill (&formal->name);
491 free (formal);
492}
493
252b5132
RH
494/* Pick up the formal parameters of a macro definition. */
495
39a45edc
AM
496static size_t
497do_formals (macro_entry *macro, size_t idx, sb *in)
252b5132
RH
498{
499 formal_entry **p = &macro->formals;
02ddf156 500 const char *name;
252b5132 501
057f53c1 502 idx = sb_skip_white (idx, in);
252b5132
RH
503 while (idx < in->len)
504 {
6eaeac8a 505 formal_entry *formal = new_formal ();
39a45edc 506 size_t cidx;
252b5132 507
252b5132
RH
508 idx = get_token (idx, in, &formal->name);
509 if (formal->name.len == 0)
057f53c1
JB
510 {
511 if (macro->formal_count)
512 --idx;
4ac14836 513 del_formal (formal); /* 'formal' goes out of scope. */
057f53c1
JB
514 break;
515 }
252b5132 516 idx = sb_skip_white (idx, in);
057f53c1 517 /* This is a formal. */
6eaeac8a
JB
518 name = sb_terminate (&formal->name);
519 if (! macro_mri
520 && idx < in->len
521 && in->ptr[idx] == ':'
522 && (! is_name_beginner (':')
523 || idx + 1 >= in->len
524 || ! is_part_of_name (in->ptr[idx + 1])))
525 {
526 /* Got a qualifier. */
527 sb qual;
528
529 sb_new (&qual);
530 idx = get_token (sb_skip_white (idx + 1, in), in, &qual);
531 sb_terminate (&qual);
532 if (qual.len == 0)
533 as_bad_where (macro->file,
534 macro->line,
535 _("Missing parameter qualifier for `%s' in macro `%s'"),
536 name,
537 macro->name);
538 else if (strcmp (qual.ptr, "req") == 0)
539 formal->type = FORMAL_REQUIRED;
540 else if (strcmp (qual.ptr, "vararg") == 0)
541 formal->type = FORMAL_VARARG;
542 else
543 as_bad_where (macro->file,
544 macro->line,
545 _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"),
546 qual.ptr,
547 name,
548 macro->name);
549 sb_kill (&qual);
550 idx = sb_skip_white (idx, in);
551 }
057f53c1 552 if (idx < in->len && in->ptr[idx] == '=')
252b5132 553 {
057f53c1 554 /* Got a default. */
be03cc84 555 idx = get_any_string (idx + 1, in, &formal->def);
057f53c1 556 idx = sb_skip_white (idx, in);
6eaeac8a
JB
557 if (formal->type == FORMAL_REQUIRED)
558 {
559 sb_reset (&formal->def);
560 as_warn_where (macro->file,
561 macro->line,
562 _("Pointless default value for required parameter `%s' in macro `%s'"),
563 name,
564 macro->name);
565 }
252b5132
RH
566 }
567
29f8404c 568 /* Add to macro's hash table. */
02ddf156
JB
569 if (! hash_find (macro->formal_hash, name))
570 hash_jam (macro->formal_hash, name, formal);
571 else
572 as_bad_where (macro->file,
573 macro->line,
574 _("A parameter named `%s' already exists for macro `%s'"),
575 name,
576 macro->name);
252b5132 577
057f53c1 578 formal->index = macro->formal_count++;
6eaeac8a
JB
579 *p = formal;
580 p = &formal->next;
581 if (formal->type == FORMAL_VARARG)
582 break;
057f53c1 583 cidx = idx;
252b5132 584 idx = sb_skip_comma (idx, in);
057f53c1
JB
585 if (idx != cidx && idx >= in->len)
586 {
587 idx = cidx;
588 break;
589 }
252b5132
RH
590 }
591
592 if (macro_mri)
593 {
6eaeac8a 594 formal_entry *formal = new_formal ();
252b5132
RH
595
596 /* Add a special NARG formal, which macro_expand will set to the
4c665b71 597 number of arguments. */
252b5132 598 /* The same MRI assemblers which treat '@' characters also use
4c665b71 599 the name $NARG. At least until we find an exception. */
252b5132
RH
600 if (macro_strip_at)
601 name = "$NARG";
602 else
603 name = "NARG";
604
605 sb_add_string (&formal->name, name);
606
29f8404c 607 /* Add to macro's hash table. */
02ddf156
JB
608 if (hash_find (macro->formal_hash, name))
609 as_bad_where (macro->file,
610 macro->line,
611 _("Reserved word `%s' used as parameter in macro `%s'"),
612 name,
613 macro->name);
252b5132
RH
614 hash_jam (macro->formal_hash, name, formal);
615
616 formal->index = NARG_INDEX;
617 *p = formal;
252b5132
RH
618 }
619
620 return idx;
621}
622
f19df8f7
AM
623/* Free the memory allocated to a macro. */
624
625static void
626free_macro (macro_entry *macro)
627{
628 formal_entry *formal;
629
630 for (formal = macro->formals; formal; )
631 {
632 formal_entry *f;
633
634 f = formal;
635 formal = formal->next;
636 del_formal (f);
637 }
638 hash_die (macro->formal_hash);
639 sb_kill (&macro->sub);
640 free (macro);
641}
642
252b5132
RH
643/* Define a new macro. Returns NULL on success, otherwise returns an
644 error message. If NAMEP is not NULL, *NAMEP is set to the name of
645 the macro which was defined. */
646
647const char *
39a45edc
AM
648define_macro (size_t idx, sb *in, sb *label,
649 size_t (*get_line) (sb *),
3b4dbbbf 650 const char *file, unsigned int line,
02ddf156 651 const char **namep)
252b5132
RH
652{
653 macro_entry *macro;
654 sb name;
02ddf156 655 const char *error = NULL;
252b5132 656
325801bd 657 macro = XNEW (macro_entry);
252b5132
RH
658 sb_new (&macro->sub);
659 sb_new (&name);
02ddf156
JB
660 macro->file = file;
661 macro->line = line;
252b5132
RH
662
663 macro->formal_count = 0;
664 macro->formals = 0;
4c665b71 665 macro->formal_hash = hash_new_sized (7);
252b5132
RH
666
667 idx = sb_skip_white (idx, in);
668 if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))
02ddf156 669 error = _("unexpected end of file in macro `%s' definition");
252b5132
RH
670 if (label != NULL && label->len != 0)
671 {
672 sb_add_sb (&name, label);
02ddf156 673 macro->name = sb_terminate (&name);
252b5132
RH
674 if (idx < in->len && in->ptr[idx] == '(')
675 {
29f8404c 676 /* It's the label: MACRO (formals,...) sort */
252b5132 677 idx = do_formals (macro, idx + 1, in);
02ddf156
JB
678 if (idx < in->len && in->ptr[idx] == ')')
679 idx = sb_skip_white (idx + 1, in);
680 else if (!error)
681 error = _("missing `)' after formals in macro definition `%s'");
252b5132
RH
682 }
683 else
684 {
29f8404c 685 /* It's the label: MACRO formals,... sort */
252b5132
RH
686 idx = do_formals (macro, idx, in);
687 }
688 }
689 else
690 {
39a45edc 691 size_t cidx;
057f53c1 692
252b5132 693 idx = get_token (idx, in, &name);
02ddf156 694 macro->name = sb_terminate (&name);
057f53c1 695 if (name.len == 0)
02ddf156 696 error = _("Missing macro name");
057f53c1
JB
697 cidx = sb_skip_white (idx, in);
698 idx = sb_skip_comma (cidx, in);
699 if (idx == cidx || idx < in->len)
700 idx = do_formals (macro, idx, in);
701 else
702 idx = cidx;
252b5132 703 }
02ddf156
JB
704 if (!error && idx < in->len)
705 error = _("Bad parameter list for macro `%s'");
252b5132 706
29f8404c 707 /* And stick it in the macro hash table. */
252b5132 708 for (idx = 0; idx < name.len; idx++)
3882b010 709 name.ptr[idx] = TOLOWER (name.ptr[idx]);
02ddf156
JB
710 if (hash_find (macro_hash, macro->name))
711 error = _("Macro `%s' was already defined");
712 if (!error)
5a49b8ac 713 error = hash_jam (macro_hash, macro->name, (void *) macro);
252b5132
RH
714
715 if (namep != NULL)
02ddf156
JB
716 *namep = macro->name;
717
718 if (!error)
719 macro_defined = 1;
720 else
721 free_macro (macro);
252b5132 722
02ddf156 723 return error;
252b5132
RH
724}
725
726/* Scan a token, and then skip KIND. */
727
39a45edc
AM
728static size_t
729get_apost_token (size_t idx, sb *in, sb *name, int kind)
252b5132
RH
730{
731 idx = get_token (idx, in, name);
732 if (idx < in->len
733 && in->ptr[idx] == kind
734 && (! macro_mri || macro_strip_at)
735 && (! macro_strip_at || kind == '@'))
736 idx++;
737 return idx;
738}
739
740/* Substitute the actual value for a formal parameter. */
741
39a45edc
AM
742static size_t
743sub_actual (size_t start, sb *in, sb *t, struct hash_control *formal_hash,
254d758c 744 int kind, sb *out, int copyifnotthere)
252b5132 745{
39a45edc 746 size_t src;
252b5132
RH
747 formal_entry *ptr;
748
749 src = get_apost_token (start, in, t, kind);
750 /* See if it's in the macro's hash table, unless this is
751 macro_strip_at and kind is '@' and the token did not end in '@'. */
752 if (macro_strip_at
753 && kind == '@'
754 && (src == start || in->ptr[src - 1] != '@'))
755 ptr = NULL;
756 else
757 ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
758 if (ptr)
759 {
760 if (ptr->actual.len)
761 {
762 sb_add_sb (out, &ptr->actual);
763 }
764 else
765 {
766 sb_add_sb (out, &ptr->def);
767 }
768 }
769 else if (kind == '&')
770 {
771 /* Doing this permits people to use & in macro bodies. */
772 sb_add_char (out, '&');
c1ed1235 773 sb_add_sb (out, t);
d1f52f54
AM
774 if (src != start && in->ptr[src - 1] == '&')
775 sb_add_char (out, '&');
252b5132
RH
776 }
777 else if (copyifnotthere)
778 {
779 sb_add_sb (out, t);
780 }
29f8404c 781 else
252b5132
RH
782 {
783 sb_add_char (out, '\\');
784 sb_add_sb (out, t);
785 }
786 return src;
787}
788
789/* Expand the body of a macro. */
790
791static const char *
254d758c 792macro_expand_body (sb *in, sb *out, formal_entry *formals,
02ddf156 793 struct hash_control *formal_hash, const macro_entry *macro)
252b5132
RH
794{
795 sb t;
39a45edc
AM
796 size_t src = 0;
797 int inquote = 0, macro_line = 0;
252b5132 798 formal_entry *loclist = NULL;
02ddf156 799 const char *err = NULL;
252b5132
RH
800
801 sb_new (&t);
802
02ddf156 803 while (src < in->len && !err)
252b5132
RH
804 {
805 if (in->ptr[src] == '&')
806 {
807 sb_reset (&t);
808 if (macro_mri)
809 {
810 if (src + 1 < in->len && in->ptr[src + 1] == '&')
811 src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
812 else
813 sb_add_char (out, in->ptr[src++]);
814 }
815 else
816 {
33eaf5de 817 /* Permit macro parameter substitution delineated with
d1f52f54 818 an '&' prefix and optional '&' suffix. */
252b5132
RH
819 src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
820 }
821 }
822 else if (in->ptr[src] == '\\')
823 {
824 src++;
5e75c3ab 825 if (src < in->len && in->ptr[src] == '(')
252b5132 826 {
29f8404c 827 /* Sub in till the next ')' literally. */
252b5132
RH
828 src++;
829 while (src < in->len && in->ptr[src] != ')')
830 {
831 sb_add_char (out, in->ptr[src++]);
832 }
02ddf156 833 if (src < in->len)
252b5132 834 src++;
02ddf156
JB
835 else if (!macro)
836 err = _("missing `)'");
252b5132 837 else
02ddf156 838 as_bad_where (macro->file, macro->line + macro_line, _("missing `)'"));
252b5132 839 }
5e75c3ab 840 else if (src < in->len && in->ptr[src] == '@')
252b5132 841 {
29f8404c 842 /* Sub in the macro invocation number. */
252b5132 843
98a4fc78 844 char buffer[12];
252b5132 845 src++;
a2984248 846 sprintf (buffer, "%d", macro_number);
252b5132
RH
847 sb_add_string (out, buffer);
848 }
5e75c3ab 849 else if (src < in->len && in->ptr[src] == '&')
252b5132
RH
850 {
851 /* This is a preprocessor variable name, we don't do them
29f8404c 852 here. */
252b5132
RH
853 sb_add_char (out, '\\');
854 sb_add_char (out, '&');
855 src++;
856 }
5e75c3ab 857 else if (macro_mri && src < in->len && ISALNUM (in->ptr[src]))
252b5132
RH
858 {
859 int ind;
860 formal_entry *f;
861
3882b010 862 if (ISDIGIT (in->ptr[src]))
252b5132 863 ind = in->ptr[src] - '0';
3882b010 864 else if (ISUPPER (in->ptr[src]))
252b5132
RH
865 ind = in->ptr[src] - 'A' + 10;
866 else
867 ind = in->ptr[src] - 'a' + 10;
868 ++src;
869 for (f = formals; f != NULL; f = f->next)
870 {
871 if (f->index == ind - 1)
872 {
873 if (f->actual.len != 0)
874 sb_add_sb (out, &f->actual);
875 else
876 sb_add_sb (out, &f->def);
877 break;
878 }
879 }
880 }
881 else
882 {
883 sb_reset (&t);
884 src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
885 }
886 }
887 else if ((macro_alternate || macro_mri)
5e75c3ab 888 && is_name_beginner (in->ptr[src])
252b5132
RH
889 && (! inquote
890 || ! macro_strip_at
891 || (src > 0 && in->ptr[src - 1] == '@')))
892 {
02ddf156 893 if (! macro
252b5132
RH
894 || src + 5 >= in->len
895 || strncasecmp (in->ptr + src, "LOCAL", 5) != 0
aa27de95
NC
896 || ! ISWHITE (in->ptr[src + 5])
897 /* PR 11507: Skip keyword LOCAL if it is found inside a quoted string. */
898 || inquote)
252b5132
RH
899 {
900 sb_reset (&t);
901 src = sub_actual (src, in, &t, formal_hash,
902 (macro_strip_at && inquote) ? '@' : '\'',
903 out, 1);
904 }
905 else
906 {
252b5132 907 src = sb_skip_white (src + 5, in);
fea17916 908 while (in->ptr[src] != '\n')
252b5132 909 {
02ddf156 910 const char *name;
6eaeac8a 911 formal_entry *f = new_formal ();
252b5132 912
252b5132 913 src = get_token (src, in, &f->name);
02ddf156
JB
914 name = sb_terminate (&f->name);
915 if (! hash_find (formal_hash, name))
916 {
917 static int loccnt;
918 char buf[20];
252b5132 919
02ddf156
JB
920 f->index = LOCAL_INDEX;
921 f->next = loclist;
922 loclist = f;
923
924 sprintf (buf, IS_ELF ? ".LL%04x" : "LL%04x", ++loccnt);
925 sb_add_string (&f->actual, buf);
926
927 err = hash_jam (formal_hash, name, f);
928 if (err != NULL)
929 break;
930 }
931 else
932 {
933 as_bad_where (macro->file,
934 macro->line + macro_line,
935 _("`%s' was already used as parameter (or another local) name"),
936 name);
6eaeac8a 937 del_formal (f);
02ddf156 938 }
252b5132
RH
939
940 src = sb_skip_comma (src, in);
941 }
942 }
943 }
252b5132
RH
944 else if (in->ptr[src] == '"'
945 || (macro_mri && in->ptr[src] == '\''))
946 {
947 inquote = !inquote;
948 sb_add_char (out, in->ptr[src++]);
949 }
950 else if (in->ptr[src] == '@' && macro_strip_at)
951 {
952 ++src;
953 if (src < in->len
954 && in->ptr[src] == '@')
955 {
956 sb_add_char (out, '@');
957 ++src;
958 }
959 }
960 else if (macro_mri
961 && in->ptr[src] == '='
962 && src + 1 < in->len
963 && in->ptr[src + 1] == '=')
964 {
965 formal_entry *ptr;
966
967 sb_reset (&t);
968 src = get_token (src + 2, in, &t);
969 ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t));
970 if (ptr == NULL)
971 {
972 /* FIXME: We should really return a warning string here,
4c665b71
RM
973 but we can't, because the == might be in the MRI
974 comment field, and, since the nature of the MRI
975 comment field depends upon the exact instruction
976 being used, we don't have enough information here to
977 figure out whether it is or not. Instead, we leave
978 the == in place, which should cause a syntax error if
979 it is not in a comment. */
252b5132
RH
980 sb_add_char (out, '=');
981 sb_add_char (out, '=');
982 sb_add_sb (out, &t);
983 }
984 else
985 {
986 if (ptr->actual.len)
987 {
988 sb_add_string (out, "-1");
989 }
990 else
991 {
992 sb_add_char (out, '0');
993 }
994 }
995 }
996 else
997 {
02ddf156
JB
998 if (in->ptr[src] == '\n')
999 ++macro_line;
252b5132
RH
1000 sb_add_char (out, in->ptr[src++]);
1001 }
1002 }
1003
1004 sb_kill (&t);
1005
1006 while (loclist != NULL)
1007 {
1008 formal_entry *f;
818236e5 1009 const char *name;
252b5132
RH
1010
1011 f = loclist->next;
818236e5
AM
1012 name = sb_terminate (&loclist->name);
1013 hash_delete (formal_hash, name, f == NULL);
6eaeac8a 1014 del_formal (loclist);
252b5132
RH
1015 loclist = f;
1016 }
1017
02ddf156 1018 return err;
252b5132
RH
1019}
1020
1021/* Assign values to the formal parameters of a macro, and expand the
1022 body. */
1023
1024static const char *
39a45edc 1025macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
252b5132
RH
1026{
1027 sb t;
1028 formal_entry *ptr;
1029 formal_entry *f;
252b5132
RH
1030 int is_keyword = 0;
1031 int narg = 0;
6eaeac8a 1032 const char *err = NULL;
252b5132
RH
1033
1034 sb_new (&t);
29f8404c
KH
1035
1036 /* Reset any old value the actuals may have. */
252b5132 1037 for (f = m->formals; f; f = f->next)
29f8404c 1038 sb_reset (&f->actual);
252b5132
RH
1039 f = m->formals;
1040 while (f != NULL && f->index < 0)
1041 f = f->next;
1042
1043 if (macro_mri)
1044 {
1045 /* The macro may be called with an optional qualifier, which may
4c665b71 1046 be referred to in the macro body as \0. */
252b5132 1047 if (idx < in->len && in->ptr[idx] == '.')
d1a6c242
KH
1048 {
1049 /* The Microtec assembler ignores this if followed by a white space.
1050 (Macro invocation with empty extension) */
1051 idx++;
1052 if ( idx < in->len
1053 && in->ptr[idx] != ' '
1054 && in->ptr[idx] != '\t')
1055 {
6eaeac8a 1056 formal_entry *n = new_formal ();
d1a6c242 1057
d1a6c242
KH
1058 n->index = QUAL_INDEX;
1059
1060 n->next = m->formals;
1061 m->formals = n;
1062
be03cc84 1063 idx = get_any_string (idx, in, &n->actual);
d1a6c242
KH
1064 }
1065 }
1066 }
252b5132 1067
29f8404c 1068 /* Peel off the actuals and store them away in the hash tables' actuals. */
252b5132 1069 idx = sb_skip_white (idx, in);
fea17916 1070 while (idx < in->len)
252b5132 1071 {
39a45edc 1072 size_t scan;
252b5132 1073
29f8404c 1074 /* Look and see if it's a positional or keyword arg. */
252b5132
RH
1075 scan = idx;
1076 while (scan < in->len
1077 && !ISSEP (in->ptr[scan])
1078 && !(macro_mri && in->ptr[scan] == '\'')
1079 && (!macro_alternate && in->ptr[scan] != '='))
1080 scan++;
1081 if (scan < in->len && !macro_alternate && in->ptr[scan] == '=')
1082 {
1083 is_keyword = 1;
1084
1085 /* It's OK to go from positional to keyword. */
1086
1087 /* This is a keyword arg, fetch the formal name and
29f8404c 1088 then the actual stuff. */
252b5132
RH
1089 sb_reset (&t);
1090 idx = get_token (idx, in, &t);
1091 if (in->ptr[idx] != '=')
6eaeac8a
JB
1092 {
1093 err = _("confusion in formal parameters");
1094 break;
1095 }
252b5132 1096
29f8404c 1097 /* Lookup the formal in the macro's list. */
252b5132
RH
1098 ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
1099 if (!ptr)
c0ba1095
AM
1100 {
1101 as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
1102 t.ptr,
1103 m->name);
1104 sb_reset (&t);
1105 idx = get_any_string (idx + 1, in, &t);
1106 }
252b5132
RH
1107 else
1108 {
29f8404c 1109 /* Insert this value into the right place. */
6eaeac8a
JB
1110 if (ptr->actual.len)
1111 {
1112 as_warn (_("Value for parameter `%s' of macro `%s' was already specified"),
1113 ptr->name.ptr,
1114 m->name);
1115 sb_reset (&ptr->actual);
1116 }
be03cc84 1117 idx = get_any_string (idx + 1, in, &ptr->actual);
252b5132
RH
1118 if (ptr->actual.len > 0)
1119 ++narg;
1120 }
1121 }
1122 else
1123 {
252b5132 1124 if (is_keyword)
6eaeac8a
JB
1125 {
1126 err = _("can't mix positional and keyword arguments");
1127 break;
1128 }
252b5132
RH
1129
1130 if (!f)
1131 {
1132 formal_entry **pf;
1133 int c;
1134
1135 if (!macro_mri)
6eaeac8a
JB
1136 {
1137 err = _("too many positional arguments");
1138 break;
1139 }
252b5132 1140
6eaeac8a 1141 f = new_formal ();
252b5132
RH
1142
1143 c = -1;
1144 for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
1145 if ((*pf)->index >= c)
1146 c = (*pf)->index + 1;
1147 if (c == -1)
1148 c = 0;
1149 *pf = f;
1150 f->index = c;
1151 }
1152
6eaeac8a 1153 if (f->type != FORMAL_VARARG)
be03cc84 1154 idx = get_any_string (idx, in, &f->actual);
6eaeac8a
JB
1155 else
1156 {
1157 sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx);
1158 idx = in->len;
1159 }
252b5132
RH
1160 if (f->actual.len > 0)
1161 ++narg;
1162 do
1163 {
1164 f = f->next;
1165 }
1166 while (f != NULL && f->index < 0);
1167 }
1168
1169 if (! macro_mri)
1170 idx = sb_skip_comma (idx, in);
1171 else
1172 {
1173 if (in->ptr[idx] == ',')
1174 ++idx;
1175 if (ISWHITE (in->ptr[idx]))
1176 break;
1177 }
1178 }
1179
6eaeac8a 1180 if (! err)
252b5132 1181 {
6eaeac8a
JB
1182 for (ptr = m->formals; ptr; ptr = ptr->next)
1183 {
1184 if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0)
1185 as_bad (_("Missing value for required parameter `%s' of macro `%s'"),
1186 ptr->name.ptr,
1187 m->name);
1188 }
252b5132 1189
6eaeac8a
JB
1190 if (macro_mri)
1191 {
1192 char buffer[20];
1193
1194 sb_reset (&t);
1195 sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
1196 ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
1197 sprintf (buffer, "%d", narg);
1198 sb_add_string (&ptr->actual, buffer);
1199 }
1200
1201 err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
1202 }
252b5132
RH
1203
1204 /* Discard any unnamed formal arguments. */
1205 if (macro_mri)
1206 {
1207 formal_entry **pf;
1208
1209 pf = &m->formals;
1210 while (*pf != NULL)
1211 {
1212 if ((*pf)->name.len != 0)
1213 pf = &(*pf)->next;
1214 else
1215 {
252b5132 1216 f = (*pf)->next;
6eaeac8a 1217 del_formal (*pf);
252b5132
RH
1218 *pf = f;
1219 }
1220 }
1221 }
1222
1223 sb_kill (&t);
02ddf156
JB
1224 if (!err)
1225 macro_number++;
252b5132 1226
02ddf156 1227 return err;
252b5132
RH
1228}
1229
1230/* Check for a macro. If one is found, put the expansion into
fea17916 1231 *EXPAND. Return 1 if a macro is found, 0 otherwise. */
252b5132
RH
1232
1233int
254d758c
KH
1234check_macro (const char *line, sb *expand,
1235 const char **error, macro_entry **info)
252b5132
RH
1236{
1237 const char *s;
91d6fa6a 1238 char *copy, *cls;
252b5132
RH
1239 macro_entry *macro;
1240 sb line_sb;
1241
5e75c3ab 1242 if (! is_name_beginner (*line)
252b5132
RH
1243 && (! macro_mri || *line != '.'))
1244 return 0;
1245
1246 s = line + 1;
5e75c3ab
JB
1247 while (is_part_of_name (*s))
1248 ++s;
1249 if (is_name_ender (*s))
252b5132
RH
1250 ++s;
1251
29a2809e 1252 copy = xmemdup0 (line, s - line);
91d6fa6a
NC
1253 for (cls = copy; *cls != '\0'; cls ++)
1254 *cls = TOLOWER (*cls);
252b5132
RH
1255
1256 macro = (macro_entry *) hash_find (macro_hash, copy);
e1fa0163 1257 free (copy);
252b5132
RH
1258
1259 if (macro == NULL)
1260 return 0;
1261
1262 /* Wrap the line up in an sb. */
1263 sb_new (&line_sb);
1264 while (*s != '\0' && *s != '\n' && *s != '\r')
1265 sb_add_char (&line_sb, *s++);
1266
1267 sb_new (expand);
fea17916 1268 *error = macro_expand (0, &line_sb, macro, expand);
252b5132
RH
1269
1270 sb_kill (&line_sb);
1271
29f8404c 1272 /* Export the macro information if requested. */
9f10757c
TW
1273 if (info)
1274 *info = macro;
1275
252b5132
RH
1276 return 1;
1277}
1278
1279/* Delete a macro. */
1280
1281void
254d758c 1282delete_macro (const char *name)
252b5132 1283{
e6ca91be
JB
1284 char *copy;
1285 size_t i, len;
1286 macro_entry *macro;
1287
1288 len = strlen (name);
add39d23 1289 copy = XNEWVEC (char, len + 1);
e6ca91be
JB
1290 for (i = 0; i < len; ++i)
1291 copy[i] = TOLOWER (name[i]);
1292 copy[i] = '\0';
1293
818236e5
AM
1294 /* We can only ask hash_delete to free memory if we are deleting
1295 macros in reverse order to their definition.
1296 So just clear out the entry. */
1e9cc1c2 1297 if ((macro = (macro_entry *) hash_find (macro_hash, copy)) != NULL)
e6ca91be
JB
1298 {
1299 hash_jam (macro_hash, copy, NULL);
1300 free_macro (macro);
1301 }
1302 else
33eaf5de 1303 as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
e1fa0163 1304 free (copy);
252b5132
RH
1305}
1306
1307/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a
1308 combined macro definition and execution. This returns NULL on
1309 success, or an error message otherwise. */
1310
1311const char *
39a45edc 1312expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
252b5132 1313{
252b5132
RH
1314 sb sub;
1315 formal_entry f;
1316 struct hash_control *h;
1317 const char *err;
1318
252b5132
RH
1319 idx = sb_skip_white (idx, in);
1320
1321 sb_new (&sub);
ca3bc58f 1322 if (! buffer_and_nest (NULL, "ENDR", &sub, get_line))
252b5132 1323 return _("unexpected end of file in irp or irpc");
29f8404c 1324
252b5132
RH
1325 sb_new (&f.name);
1326 sb_new (&f.def);
1327 sb_new (&f.actual);
1328
1329 idx = get_token (idx, in, &f.name);
1330 if (f.name.len == 0)
1331 return _("missing model parameter");
1332
1333 h = hash_new ();
1334 err = hash_jam (h, sb_terminate (&f.name), &f);
1335 if (err != NULL)
1336 return err;
1337
1338 f.index = 1;
1339 f.next = NULL;
6eaeac8a 1340 f.type = FORMAL_OPTIONAL;
252b5132
RH
1341
1342 sb_reset (out);
1343
1344 idx = sb_skip_comma (idx, in);
fea17916 1345 if (idx >= in->len)
252b5132
RH
1346 {
1347 /* Expand once with a null string. */
fea17916 1348 err = macro_expand_body (&sub, out, &f, h, 0);
252b5132
RH
1349 }
1350 else
1351 {
465e5617
NC
1352 bfd_boolean in_quotes = FALSE;
1353
252b5132 1354 if (irpc && in->ptr[idx] == '"')
465e5617
NC
1355 {
1356 in_quotes = TRUE;
1357 ++idx;
1358 }
1359
fea17916 1360 while (idx < in->len)
252b5132
RH
1361 {
1362 if (!irpc)
be03cc84 1363 idx = get_any_string (idx, in, &f.actual);
252b5132
RH
1364 else
1365 {
1366 if (in->ptr[idx] == '"')
1367 {
39a45edc 1368 size_t nxt;
252b5132 1369
465e5617
NC
1370 if (irpc)
1371 in_quotes = ! in_quotes;
4c665b71 1372
252b5132 1373 nxt = sb_skip_white (idx + 1, in);
fea17916 1374 if (nxt >= in->len)
252b5132
RH
1375 {
1376 idx = nxt;
1377 break;
1378 }
1379 }
1380 sb_reset (&f.actual);
1381 sb_add_char (&f.actual, in->ptr[idx]);
1382 ++idx;
1383 }
465e5617 1384
fea17916 1385 err = macro_expand_body (&sub, out, &f, h, 0);
252b5132 1386 if (err != NULL)
02ddf156 1387 break;
252b5132
RH
1388 if (!irpc)
1389 idx = sb_skip_comma (idx, in);
465e5617 1390 else if (! in_quotes)
252b5132
RH
1391 idx = sb_skip_white (idx, in);
1392 }
1393 }
1394
1395 hash_die (h);
6eaeac8a
JB
1396 sb_kill (&f.actual);
1397 sb_kill (&f.def);
1398 sb_kill (&f.name);
252b5132
RH
1399 sb_kill (&sub);
1400
02ddf156 1401 return err;
252b5132 1402}
This page took 0.975695 seconds and 4 git commands to generate.