A few comment cleanups
[deliverable/binutils-gdb.git] / gas / macro.c
CommitLineData
fea17916 1/* macro.c - macro support for gas
4b95cf5c 2 Copyright (C) 1994-2014 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 {
226 char *saved_input_line_pointer = input_line_pointer;
227 char saved_eol_char = ptr->ptr[ptr->len];
228
229 ptr->ptr[ptr->len] = '\0';
230 input_line_pointer = ptr->ptr + i + 8;
231 s_app_line (0);
232 ptr->ptr[ptr->len] = saved_eol_char;
233 input_line_pointer = saved_input_line_pointer;
234 ptr->len = line_start;
235 }
252b5132
RH
236 }
237
0822d075
NC
238 /* Add the original end-of-line char to the end and keep running. */
239 sb_add_char (ptr, more);
252b5132
RH
240 line_start = ptr->len;
241 more = get_line (ptr);
242 }
243
244 /* Return 1 on success, 0 on unexpected EOF. */
245 return depth == 0;
246}
247
248/* Pick up a token. */
249
39a45edc
AM
250static size_t
251get_token (size_t idx, sb *in, sb *name)
252b5132
RH
252{
253 if (idx < in->len
5e75c3ab 254 && is_name_beginner (in->ptr[idx]))
252b5132
RH
255 {
256 sb_add_char (name, in->ptr[idx++]);
257 while (idx < in->len
5e75c3ab
JB
258 && is_part_of_name (in->ptr[idx]))
259 {
260 sb_add_char (name, in->ptr[idx++]);
261 }
262 if (idx < in->len
263 && is_name_ender (in->ptr[idx]))
252b5132
RH
264 {
265 sb_add_char (name, in->ptr[idx++]);
266 }
267 }
29f8404c 268 /* Ignore trailing &. */
252b5132
RH
269 if (macro_alternate && idx < in->len && in->ptr[idx] == '&')
270 idx++;
271 return idx;
272}
273
274/* Pick up a string. */
275
39a45edc
AM
276static size_t
277getstring (size_t idx, sb *in, sb *acc)
252b5132 278{
252b5132 279 while (idx < in->len
29f8404c 280 && (in->ptr[idx] == '"'
252b5132
RH
281 || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
282 || (in->ptr[idx] == '\'' && macro_alternate)))
283 {
2f6178c1 284 if (in->ptr[idx] == '<')
252b5132
RH
285 {
286 int nest = 0;
287 idx++;
0e31b3e1 288 while ((in->ptr[idx] != '>' || nest)
252b5132
RH
289 && idx < in->len)
290 {
291 if (in->ptr[idx] == '!')
292 {
29f8404c 293 idx++;
252b5132
RH
294 sb_add_char (acc, in->ptr[idx++]);
295 }
296 else
297 {
0e31b3e1 298 if (in->ptr[idx] == '>')
252b5132 299 nest--;
0e31b3e1 300 if (in->ptr[idx] == '<')
252b5132
RH
301 nest++;
302 sb_add_char (acc, in->ptr[idx++]);
303 }
304 }
305 idx++;
306 }
307 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
308 {
309 char tchar = in->ptr[idx];
c06ae4f2 310 int escaped = 0;
29f8404c 311
252b5132 312 idx++;
29f8404c 313
252b5132
RH
314 while (idx < in->len)
315 {
29f8404c 316 if (in->ptr[idx - 1] == '\\')
c06ae4f2
UC
317 escaped ^= 1;
318 else
319 escaped = 0;
320
252b5132
RH
321 if (macro_alternate && in->ptr[idx] == '!')
322 {
e972090a 323 idx ++;
29f8404c 324
1994a7c7
NC
325 sb_add_char (acc, in->ptr[idx]);
326
e972090a 327 idx ++;
252b5132 328 }
c06ae4f2
UC
329 else if (escaped && in->ptr[idx] == tchar)
330 {
331 sb_add_char (acc, tchar);
e972090a 332 idx ++;
c06ae4f2 333 }
252b5132
RH
334 else
335 {
336 if (in->ptr[idx] == tchar)
337 {
e972090a 338 idx ++;
29f8404c 339
252b5132
RH
340 if (idx >= in->len || in->ptr[idx] != tchar)
341 break;
342 }
29f8404c 343
252b5132 344 sb_add_char (acc, in->ptr[idx]);
e972090a 345 idx ++;
252b5132
RH
346 }
347 }
348 }
349 }
29f8404c 350
252b5132
RH
351 return idx;
352}
353
354/* Fetch string from the input stream,
355 rules:
356 'Bxyx<whitespace> -> return 'Bxyza
df40eaf9
NC
357 %<expr> -> return string of decimal value of <expr>
358 "string" -> return string
2f6178c1 359 (string) -> return (string-including-whitespaces)
df40eaf9 360 xyx<whitespace> -> return xyz. */
252b5132 361
39a45edc
AM
362static size_t
363get_any_string (size_t idx, sb *in, sb *out)
252b5132
RH
364{
365 sb_reset (out);
366 idx = sb_skip_white (idx, in);
367
368 if (idx < in->len)
369 {
9df59bba 370 if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
252b5132
RH
371 {
372 while (!ISSEP (in->ptr[idx]))
373 sb_add_char (out, in->ptr[idx++]);
374 }
be03cc84 375 else if (in->ptr[idx] == '%' && macro_alternate)
252b5132 376 {
39a45edc 377 offsetT val;
252b5132 378 char buf[20];
df40eaf9 379
29f8404c 380 /* Turns the next expression into a string. */
06f030db 381 /* xgettext: no-c-format */
252b5132
RH
382 idx = (*macro_expr) (_("% operator needs absolute expression"),
383 idx + 1,
384 in,
385 &val);
39a45edc 386 sprintf (buf, "%" BFD_VMA_FMT "d", val);
252b5132
RH
387 sb_add_string (out, buf);
388 }
389 else if (in->ptr[idx] == '"'
390 || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
391 || (macro_alternate && in->ptr[idx] == '\''))
392 {
9f6f925e 393 if (macro_alternate && ! macro_strip_at && in->ptr[idx] != '<')
252b5132 394 {
29f8404c 395 /* Keep the quotes. */
9f6f925e 396 sb_add_char (out, '"');
252b5132 397 idx = getstring (idx, in, out);
9f6f925e 398 sb_add_char (out, '"');
252b5132
RH
399 }
400 else
401 {
402 idx = getstring (idx, in, out);
403 }
404 }
29f8404c 405 else
252b5132 406 {
4ac14836 407 char *br_buf = (char *) xmalloc (1);
0e31b3e1
JB
408 char *in_br = br_buf;
409
410 *in_br = '\0';
29f8404c 411 while (idx < in->len
0e31b3e1
JB
412 && (*in_br
413 || (in->ptr[idx] != ' '
414 && in->ptr[idx] != '\t'))
be03cc84
JB
415 && in->ptr[idx] != ','
416 && (in->ptr[idx] != '<'
417 || (! macro_alternate && ! macro_mri)))
252b5132 418 {
0e31b3e1 419 char tchar = in->ptr[idx];
df40eaf9 420
0e31b3e1
JB
421 switch (tchar)
422 {
423 case '"':
424 case '\'':
252b5132
RH
425 sb_add_char (out, in->ptr[idx++]);
426 while (idx < in->len
427 && in->ptr[idx] != tchar)
29f8404c 428 sb_add_char (out, in->ptr[idx++]);
252b5132 429 if (idx == in->len)
4ac14836
NC
430 {
431 free (br_buf);
432 return idx;
433 }
0e31b3e1
JB
434 break;
435 case '(':
436 case '[':
437 if (in_br > br_buf)
438 --in_br;
439 else
440 {
4ac14836
NC
441 br_buf = (char *) xmalloc (strlen (in_br) + 2);
442 strcpy (br_buf + 1, in_br);
443 free (in_br);
0e31b3e1
JB
444 in_br = br_buf;
445 }
446 *in_br = tchar;
447 break;
448 case ')':
449 if (*in_br == '(')
450 ++in_br;
451 break;
452 case ']':
453 if (*in_br == '[')
454 ++in_br;
455 break;
252b5132 456 }
0e31b3e1
JB
457 sb_add_char (out, tchar);
458 ++idx;
252b5132 459 }
4ac14836 460 free (br_buf);
252b5132
RH
461 }
462 }
463
464 return idx;
465}
466
6eaeac8a
JB
467/* Allocate a new formal. */
468
469static formal_entry *
470new_formal (void)
471{
472 formal_entry *formal;
473
1e9cc1c2 474 formal = (formal_entry *) xmalloc (sizeof (formal_entry));
6eaeac8a
JB
475
476 sb_new (&formal->name);
477 sb_new (&formal->def);
478 sb_new (&formal->actual);
479 formal->next = NULL;
480 formal->type = FORMAL_OPTIONAL;
481 return formal;
482}
483
484/* Free a formal. */
485
486static void
487del_formal (formal_entry *formal)
488{
489 sb_kill (&formal->actual);
490 sb_kill (&formal->def);
491 sb_kill (&formal->name);
492 free (formal);
493}
494
252b5132
RH
495/* Pick up the formal parameters of a macro definition. */
496
39a45edc
AM
497static size_t
498do_formals (macro_entry *macro, size_t idx, sb *in)
252b5132
RH
499{
500 formal_entry **p = &macro->formals;
02ddf156 501 const char *name;
252b5132 502
057f53c1 503 idx = sb_skip_white (idx, in);
252b5132
RH
504 while (idx < in->len)
505 {
6eaeac8a 506 formal_entry *formal = new_formal ();
39a45edc 507 size_t cidx;
252b5132 508
252b5132
RH
509 idx = get_token (idx, in, &formal->name);
510 if (formal->name.len == 0)
057f53c1
JB
511 {
512 if (macro->formal_count)
513 --idx;
4ac14836 514 del_formal (formal); /* 'formal' goes out of scope. */
057f53c1
JB
515 break;
516 }
252b5132 517 idx = sb_skip_white (idx, in);
057f53c1 518 /* This is a formal. */
6eaeac8a
JB
519 name = sb_terminate (&formal->name);
520 if (! macro_mri
521 && idx < in->len
522 && in->ptr[idx] == ':'
523 && (! is_name_beginner (':')
524 || idx + 1 >= in->len
525 || ! is_part_of_name (in->ptr[idx + 1])))
526 {
527 /* Got a qualifier. */
528 sb qual;
529
530 sb_new (&qual);
531 idx = get_token (sb_skip_white (idx + 1, in), in, &qual);
532 sb_terminate (&qual);
533 if (qual.len == 0)
534 as_bad_where (macro->file,
535 macro->line,
536 _("Missing parameter qualifier for `%s' in macro `%s'"),
537 name,
538 macro->name);
539 else if (strcmp (qual.ptr, "req") == 0)
540 formal->type = FORMAL_REQUIRED;
541 else if (strcmp (qual.ptr, "vararg") == 0)
542 formal->type = FORMAL_VARARG;
543 else
544 as_bad_where (macro->file,
545 macro->line,
546 _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"),
547 qual.ptr,
548 name,
549 macro->name);
550 sb_kill (&qual);
551 idx = sb_skip_white (idx, in);
552 }
057f53c1 553 if (idx < in->len && in->ptr[idx] == '=')
252b5132 554 {
057f53c1 555 /* Got a default. */
be03cc84 556 idx = get_any_string (idx + 1, in, &formal->def);
057f53c1 557 idx = sb_skip_white (idx, in);
6eaeac8a
JB
558 if (formal->type == FORMAL_REQUIRED)
559 {
560 sb_reset (&formal->def);
561 as_warn_where (macro->file,
562 macro->line,
563 _("Pointless default value for required parameter `%s' in macro `%s'"),
564 name,
565 macro->name);
566 }
252b5132
RH
567 }
568
29f8404c 569 /* Add to macro's hash table. */
02ddf156
JB
570 if (! hash_find (macro->formal_hash, name))
571 hash_jam (macro->formal_hash, name, formal);
572 else
573 as_bad_where (macro->file,
574 macro->line,
575 _("A parameter named `%s' already exists for macro `%s'"),
576 name,
577 macro->name);
252b5132 578
057f53c1 579 formal->index = macro->formal_count++;
6eaeac8a
JB
580 *p = formal;
581 p = &formal->next;
582 if (formal->type == FORMAL_VARARG)
583 break;
057f53c1 584 cidx = idx;
252b5132 585 idx = sb_skip_comma (idx, in);
057f53c1
JB
586 if (idx != cidx && idx >= in->len)
587 {
588 idx = cidx;
589 break;
590 }
252b5132
RH
591 }
592
593 if (macro_mri)
594 {
6eaeac8a 595 formal_entry *formal = new_formal ();
252b5132
RH
596
597 /* Add a special NARG formal, which macro_expand will set to the
4c665b71 598 number of arguments. */
252b5132 599 /* The same MRI assemblers which treat '@' characters also use
4c665b71 600 the name $NARG. At least until we find an exception. */
252b5132
RH
601 if (macro_strip_at)
602 name = "$NARG";
603 else
604 name = "NARG";
605
606 sb_add_string (&formal->name, name);
607
29f8404c 608 /* Add to macro's hash table. */
02ddf156
JB
609 if (hash_find (macro->formal_hash, name))
610 as_bad_where (macro->file,
611 macro->line,
612 _("Reserved word `%s' used as parameter in macro `%s'"),
613 name,
614 macro->name);
252b5132
RH
615 hash_jam (macro->formal_hash, name, formal);
616
617 formal->index = NARG_INDEX;
618 *p = formal;
252b5132
RH
619 }
620
621 return idx;
622}
623
f19df8f7
AM
624/* Free the memory allocated to a macro. */
625
626static void
627free_macro (macro_entry *macro)
628{
629 formal_entry *formal;
630
631 for (formal = macro->formals; formal; )
632 {
633 formal_entry *f;
634
635 f = formal;
636 formal = formal->next;
637 del_formal (f);
638 }
639 hash_die (macro->formal_hash);
640 sb_kill (&macro->sub);
641 free (macro);
642}
643
252b5132
RH
644/* Define a new macro. Returns NULL on success, otherwise returns an
645 error message. If NAMEP is not NULL, *NAMEP is set to the name of
646 the macro which was defined. */
647
648const char *
39a45edc
AM
649define_macro (size_t idx, sb *in, sb *label,
650 size_t (*get_line) (sb *),
02ddf156
JB
651 char *file, unsigned int line,
652 const char **namep)
252b5132
RH
653{
654 macro_entry *macro;
655 sb name;
02ddf156 656 const char *error = NULL;
252b5132
RH
657
658 macro = (macro_entry *) xmalloc (sizeof (macro_entry));
659 sb_new (&macro->sub);
660 sb_new (&name);
02ddf156
JB
661 macro->file = file;
662 macro->line = line;
252b5132
RH
663
664 macro->formal_count = 0;
665 macro->formals = 0;
4c665b71 666 macro->formal_hash = hash_new_sized (7);
252b5132
RH
667
668 idx = sb_skip_white (idx, in);
669 if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))
02ddf156 670 error = _("unexpected end of file in macro `%s' definition");
252b5132
RH
671 if (label != NULL && label->len != 0)
672 {
673 sb_add_sb (&name, label);
02ddf156 674 macro->name = sb_terminate (&name);
252b5132
RH
675 if (idx < in->len && in->ptr[idx] == '(')
676 {
29f8404c 677 /* It's the label: MACRO (formals,...) sort */
252b5132 678 idx = do_formals (macro, idx + 1, in);
02ddf156
JB
679 if (idx < in->len && in->ptr[idx] == ')')
680 idx = sb_skip_white (idx + 1, in);
681 else if (!error)
682 error = _("missing `)' after formals in macro definition `%s'");
252b5132
RH
683 }
684 else
685 {
29f8404c 686 /* It's the label: MACRO formals,... sort */
252b5132
RH
687 idx = do_formals (macro, idx, in);
688 }
689 }
690 else
691 {
39a45edc 692 size_t cidx;
057f53c1 693
252b5132 694 idx = get_token (idx, in, &name);
02ddf156 695 macro->name = sb_terminate (&name);
057f53c1 696 if (name.len == 0)
02ddf156 697 error = _("Missing macro name");
057f53c1
JB
698 cidx = sb_skip_white (idx, in);
699 idx = sb_skip_comma (cidx, in);
700 if (idx == cidx || idx < in->len)
701 idx = do_formals (macro, idx, in);
702 else
703 idx = cidx;
252b5132 704 }
02ddf156
JB
705 if (!error && idx < in->len)
706 error = _("Bad parameter list for macro `%s'");
252b5132 707
29f8404c 708 /* And stick it in the macro hash table. */
252b5132 709 for (idx = 0; idx < name.len; idx++)
3882b010 710 name.ptr[idx] = TOLOWER (name.ptr[idx]);
02ddf156
JB
711 if (hash_find (macro_hash, macro->name))
712 error = _("Macro `%s' was already defined");
713 if (!error)
5a49b8ac 714 error = hash_jam (macro_hash, macro->name, (void *) macro);
252b5132
RH
715
716 if (namep != NULL)
02ddf156
JB
717 *namep = macro->name;
718
719 if (!error)
720 macro_defined = 1;
721 else
722 free_macro (macro);
252b5132 723
02ddf156 724 return error;
252b5132
RH
725}
726
727/* Scan a token, and then skip KIND. */
728
39a45edc
AM
729static size_t
730get_apost_token (size_t idx, sb *in, sb *name, int kind)
252b5132
RH
731{
732 idx = get_token (idx, in, name);
733 if (idx < in->len
734 && in->ptr[idx] == kind
735 && (! macro_mri || macro_strip_at)
736 && (! macro_strip_at || kind == '@'))
737 idx++;
738 return idx;
739}
740
741/* Substitute the actual value for a formal parameter. */
742
39a45edc
AM
743static size_t
744sub_actual (size_t start, sb *in, sb *t, struct hash_control *formal_hash,
254d758c 745 int kind, sb *out, int copyifnotthere)
252b5132 746{
39a45edc 747 size_t src;
252b5132
RH
748 formal_entry *ptr;
749
750 src = get_apost_token (start, in, t, kind);
751 /* See if it's in the macro's hash table, unless this is
752 macro_strip_at and kind is '@' and the token did not end in '@'. */
753 if (macro_strip_at
754 && kind == '@'
755 && (src == start || in->ptr[src - 1] != '@'))
756 ptr = NULL;
757 else
758 ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
759 if (ptr)
760 {
761 if (ptr->actual.len)
762 {
763 sb_add_sb (out, &ptr->actual);
764 }
765 else
766 {
767 sb_add_sb (out, &ptr->def);
768 }
769 }
770 else if (kind == '&')
771 {
772 /* Doing this permits people to use & in macro bodies. */
773 sb_add_char (out, '&');
c1ed1235 774 sb_add_sb (out, t);
d1f52f54
AM
775 if (src != start && in->ptr[src - 1] == '&')
776 sb_add_char (out, '&');
252b5132
RH
777 }
778 else if (copyifnotthere)
779 {
780 sb_add_sb (out, t);
781 }
29f8404c 782 else
252b5132
RH
783 {
784 sb_add_char (out, '\\');
785 sb_add_sb (out, t);
786 }
787 return src;
788}
789
790/* Expand the body of a macro. */
791
792static const char *
254d758c 793macro_expand_body (sb *in, sb *out, formal_entry *formals,
02ddf156 794 struct hash_control *formal_hash, const macro_entry *macro)
252b5132
RH
795{
796 sb t;
39a45edc
AM
797 size_t src = 0;
798 int inquote = 0, macro_line = 0;
252b5132 799 formal_entry *loclist = NULL;
02ddf156 800 const char *err = NULL;
252b5132
RH
801
802 sb_new (&t);
803
02ddf156 804 while (src < in->len && !err)
252b5132
RH
805 {
806 if (in->ptr[src] == '&')
807 {
808 sb_reset (&t);
809 if (macro_mri)
810 {
811 if (src + 1 < in->len && in->ptr[src + 1] == '&')
812 src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
813 else
814 sb_add_char (out, in->ptr[src++]);
815 }
816 else
817 {
d1f52f54
AM
818 /* Permit macro parameter substition delineated with
819 an '&' prefix and optional '&' suffix. */
252b5132
RH
820 src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
821 }
822 }
823 else if (in->ptr[src] == '\\')
824 {
825 src++;
5e75c3ab 826 if (src < in->len && in->ptr[src] == '(')
252b5132 827 {
29f8404c 828 /* Sub in till the next ')' literally. */
252b5132
RH
829 src++;
830 while (src < in->len && in->ptr[src] != ')')
831 {
832 sb_add_char (out, in->ptr[src++]);
833 }
02ddf156 834 if (src < in->len)
252b5132 835 src++;
02ddf156
JB
836 else if (!macro)
837 err = _("missing `)'");
252b5132 838 else
02ddf156 839 as_bad_where (macro->file, macro->line + macro_line, _("missing `)'"));
252b5132 840 }
5e75c3ab 841 else if (src < in->len && in->ptr[src] == '@')
252b5132 842 {
29f8404c 843 /* Sub in the macro invocation number. */
252b5132
RH
844
845 char buffer[10];
846 src++;
a2984248 847 sprintf (buffer, "%d", macro_number);
252b5132
RH
848 sb_add_string (out, buffer);
849 }
5e75c3ab 850 else if (src < in->len && in->ptr[src] == '&')
252b5132
RH
851 {
852 /* This is a preprocessor variable name, we don't do them
29f8404c 853 here. */
252b5132
RH
854 sb_add_char (out, '\\');
855 sb_add_char (out, '&');
856 src++;
857 }
5e75c3ab 858 else if (macro_mri && src < in->len && ISALNUM (in->ptr[src]))
252b5132
RH
859 {
860 int ind;
861 formal_entry *f;
862
3882b010 863 if (ISDIGIT (in->ptr[src]))
252b5132 864 ind = in->ptr[src] - '0';
3882b010 865 else if (ISUPPER (in->ptr[src]))
252b5132
RH
866 ind = in->ptr[src] - 'A' + 10;
867 else
868 ind = in->ptr[src] - 'a' + 10;
869 ++src;
870 for (f = formals; f != NULL; f = f->next)
871 {
872 if (f->index == ind - 1)
873 {
874 if (f->actual.len != 0)
875 sb_add_sb (out, &f->actual);
876 else
877 sb_add_sb (out, &f->def);
878 break;
879 }
880 }
881 }
882 else
883 {
884 sb_reset (&t);
885 src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
886 }
887 }
888 else if ((macro_alternate || macro_mri)
5e75c3ab 889 && is_name_beginner (in->ptr[src])
252b5132
RH
890 && (! inquote
891 || ! macro_strip_at
892 || (src > 0 && in->ptr[src - 1] == '@')))
893 {
02ddf156 894 if (! macro
252b5132
RH
895 || src + 5 >= in->len
896 || strncasecmp (in->ptr + src, "LOCAL", 5) != 0
aa27de95
NC
897 || ! ISWHITE (in->ptr[src + 5])
898 /* PR 11507: Skip keyword LOCAL if it is found inside a quoted string. */
899 || inquote)
252b5132
RH
900 {
901 sb_reset (&t);
902 src = sub_actual (src, in, &t, formal_hash,
903 (macro_strip_at && inquote) ? '@' : '\'',
904 out, 1);
905 }
906 else
907 {
252b5132 908 src = sb_skip_white (src + 5, in);
fea17916 909 while (in->ptr[src] != '\n')
252b5132 910 {
02ddf156 911 const char *name;
6eaeac8a 912 formal_entry *f = new_formal ();
252b5132 913
252b5132 914 src = get_token (src, in, &f->name);
02ddf156
JB
915 name = sb_terminate (&f->name);
916 if (! hash_find (formal_hash, name))
917 {
918 static int loccnt;
919 char buf[20];
252b5132 920
02ddf156
JB
921 f->index = LOCAL_INDEX;
922 f->next = loclist;
923 loclist = f;
924
925 sprintf (buf, IS_ELF ? ".LL%04x" : "LL%04x", ++loccnt);
926 sb_add_string (&f->actual, buf);
927
928 err = hash_jam (formal_hash, name, f);
929 if (err != NULL)
930 break;
931 }
932 else
933 {
934 as_bad_where (macro->file,
935 macro->line + macro_line,
936 _("`%s' was already used as parameter (or another local) name"),
937 name);
6eaeac8a 938 del_formal (f);
02ddf156 939 }
252b5132
RH
940
941 src = sb_skip_comma (src, in);
942 }
943 }
944 }
252b5132
RH
945 else if (in->ptr[src] == '"'
946 || (macro_mri && in->ptr[src] == '\''))
947 {
948 inquote = !inquote;
949 sb_add_char (out, in->ptr[src++]);
950 }
951 else if (in->ptr[src] == '@' && macro_strip_at)
952 {
953 ++src;
954 if (src < in->len
955 && in->ptr[src] == '@')
956 {
957 sb_add_char (out, '@');
958 ++src;
959 }
960 }
961 else if (macro_mri
962 && in->ptr[src] == '='
963 && src + 1 < in->len
964 && in->ptr[src + 1] == '=')
965 {
966 formal_entry *ptr;
967
968 sb_reset (&t);
969 src = get_token (src + 2, in, &t);
970 ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t));
971 if (ptr == NULL)
972 {
973 /* FIXME: We should really return a warning string here,
4c665b71
RM
974 but we can't, because the == might be in the MRI
975 comment field, and, since the nature of the MRI
976 comment field depends upon the exact instruction
977 being used, we don't have enough information here to
978 figure out whether it is or not. Instead, we leave
979 the == in place, which should cause a syntax error if
980 it is not in a comment. */
252b5132
RH
981 sb_add_char (out, '=');
982 sb_add_char (out, '=');
983 sb_add_sb (out, &t);
984 }
985 else
986 {
987 if (ptr->actual.len)
988 {
989 sb_add_string (out, "-1");
990 }
991 else
992 {
993 sb_add_char (out, '0');
994 }
995 }
996 }
997 else
998 {
02ddf156
JB
999 if (in->ptr[src] == '\n')
1000 ++macro_line;
252b5132
RH
1001 sb_add_char (out, in->ptr[src++]);
1002 }
1003 }
1004
1005 sb_kill (&t);
1006
1007 while (loclist != NULL)
1008 {
1009 formal_entry *f;
818236e5 1010 const char *name;
252b5132
RH
1011
1012 f = loclist->next;
818236e5
AM
1013 name = sb_terminate (&loclist->name);
1014 hash_delete (formal_hash, name, f == NULL);
6eaeac8a 1015 del_formal (loclist);
252b5132
RH
1016 loclist = f;
1017 }
1018
02ddf156 1019 return err;
252b5132
RH
1020}
1021
1022/* Assign values to the formal parameters of a macro, and expand the
1023 body. */
1024
1025static const char *
39a45edc 1026macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
252b5132
RH
1027{
1028 sb t;
1029 formal_entry *ptr;
1030 formal_entry *f;
252b5132
RH
1031 int is_keyword = 0;
1032 int narg = 0;
6eaeac8a 1033 const char *err = NULL;
252b5132
RH
1034
1035 sb_new (&t);
29f8404c
KH
1036
1037 /* Reset any old value the actuals may have. */
252b5132 1038 for (f = m->formals; f; f = f->next)
29f8404c 1039 sb_reset (&f->actual);
252b5132
RH
1040 f = m->formals;
1041 while (f != NULL && f->index < 0)
1042 f = f->next;
1043
1044 if (macro_mri)
1045 {
1046 /* The macro may be called with an optional qualifier, which may
4c665b71 1047 be referred to in the macro body as \0. */
252b5132 1048 if (idx < in->len && in->ptr[idx] == '.')
d1a6c242
KH
1049 {
1050 /* The Microtec assembler ignores this if followed by a white space.
1051 (Macro invocation with empty extension) */
1052 idx++;
1053 if ( idx < in->len
1054 && in->ptr[idx] != ' '
1055 && in->ptr[idx] != '\t')
1056 {
6eaeac8a 1057 formal_entry *n = new_formal ();
d1a6c242 1058
d1a6c242
KH
1059 n->index = QUAL_INDEX;
1060
1061 n->next = m->formals;
1062 m->formals = n;
1063
be03cc84 1064 idx = get_any_string (idx, in, &n->actual);
d1a6c242
KH
1065 }
1066 }
1067 }
252b5132 1068
29f8404c 1069 /* Peel off the actuals and store them away in the hash tables' actuals. */
252b5132 1070 idx = sb_skip_white (idx, in);
fea17916 1071 while (idx < in->len)
252b5132 1072 {
39a45edc 1073 size_t scan;
252b5132 1074
29f8404c 1075 /* Look and see if it's a positional or keyword arg. */
252b5132
RH
1076 scan = idx;
1077 while (scan < in->len
1078 && !ISSEP (in->ptr[scan])
1079 && !(macro_mri && in->ptr[scan] == '\'')
1080 && (!macro_alternate && in->ptr[scan] != '='))
1081 scan++;
1082 if (scan < in->len && !macro_alternate && in->ptr[scan] == '=')
1083 {
1084 is_keyword = 1;
1085
1086 /* It's OK to go from positional to keyword. */
1087
1088 /* This is a keyword arg, fetch the formal name and
29f8404c 1089 then the actual stuff. */
252b5132
RH
1090 sb_reset (&t);
1091 idx = get_token (idx, in, &t);
1092 if (in->ptr[idx] != '=')
6eaeac8a
JB
1093 {
1094 err = _("confusion in formal parameters");
1095 break;
1096 }
252b5132 1097
29f8404c 1098 /* Lookup the formal in the macro's list. */
252b5132
RH
1099 ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
1100 if (!ptr)
c0ba1095
AM
1101 {
1102 as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
1103 t.ptr,
1104 m->name);
1105 sb_reset (&t);
1106 idx = get_any_string (idx + 1, in, &t);
1107 }
252b5132
RH
1108 else
1109 {
29f8404c 1110 /* Insert this value into the right place. */
6eaeac8a
JB
1111 if (ptr->actual.len)
1112 {
1113 as_warn (_("Value for parameter `%s' of macro `%s' was already specified"),
1114 ptr->name.ptr,
1115 m->name);
1116 sb_reset (&ptr->actual);
1117 }
be03cc84 1118 idx = get_any_string (idx + 1, in, &ptr->actual);
252b5132
RH
1119 if (ptr->actual.len > 0)
1120 ++narg;
1121 }
1122 }
1123 else
1124 {
252b5132 1125 if (is_keyword)
6eaeac8a
JB
1126 {
1127 err = _("can't mix positional and keyword arguments");
1128 break;
1129 }
252b5132
RH
1130
1131 if (!f)
1132 {
1133 formal_entry **pf;
1134 int c;
1135
1136 if (!macro_mri)
6eaeac8a
JB
1137 {
1138 err = _("too many positional arguments");
1139 break;
1140 }
252b5132 1141
6eaeac8a 1142 f = new_formal ();
252b5132
RH
1143
1144 c = -1;
1145 for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
1146 if ((*pf)->index >= c)
1147 c = (*pf)->index + 1;
1148 if (c == -1)
1149 c = 0;
1150 *pf = f;
1151 f->index = c;
1152 }
1153
6eaeac8a 1154 if (f->type != FORMAL_VARARG)
be03cc84 1155 idx = get_any_string (idx, in, &f->actual);
6eaeac8a
JB
1156 else
1157 {
1158 sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx);
1159 idx = in->len;
1160 }
252b5132
RH
1161 if (f->actual.len > 0)
1162 ++narg;
1163 do
1164 {
1165 f = f->next;
1166 }
1167 while (f != NULL && f->index < 0);
1168 }
1169
1170 if (! macro_mri)
1171 idx = sb_skip_comma (idx, in);
1172 else
1173 {
1174 if (in->ptr[idx] == ',')
1175 ++idx;
1176 if (ISWHITE (in->ptr[idx]))
1177 break;
1178 }
1179 }
1180
6eaeac8a 1181 if (! err)
252b5132 1182 {
6eaeac8a
JB
1183 for (ptr = m->formals; ptr; ptr = ptr->next)
1184 {
1185 if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0)
1186 as_bad (_("Missing value for required parameter `%s' of macro `%s'"),
1187 ptr->name.ptr,
1188 m->name);
1189 }
252b5132 1190
6eaeac8a
JB
1191 if (macro_mri)
1192 {
1193 char buffer[20];
1194
1195 sb_reset (&t);
1196 sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
1197 ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
1198 sprintf (buffer, "%d", narg);
1199 sb_add_string (&ptr->actual, buffer);
1200 }
1201
1202 err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
1203 }
252b5132
RH
1204
1205 /* Discard any unnamed formal arguments. */
1206 if (macro_mri)
1207 {
1208 formal_entry **pf;
1209
1210 pf = &m->formals;
1211 while (*pf != NULL)
1212 {
1213 if ((*pf)->name.len != 0)
1214 pf = &(*pf)->next;
1215 else
1216 {
252b5132 1217 f = (*pf)->next;
6eaeac8a 1218 del_formal (*pf);
252b5132
RH
1219 *pf = f;
1220 }
1221 }
1222 }
1223
1224 sb_kill (&t);
02ddf156
JB
1225 if (!err)
1226 macro_number++;
252b5132 1227
02ddf156 1228 return err;
252b5132
RH
1229}
1230
1231/* Check for a macro. If one is found, put the expansion into
fea17916 1232 *EXPAND. Return 1 if a macro is found, 0 otherwise. */
252b5132
RH
1233
1234int
254d758c
KH
1235check_macro (const char *line, sb *expand,
1236 const char **error, macro_entry **info)
252b5132
RH
1237{
1238 const char *s;
91d6fa6a 1239 char *copy, *cls;
252b5132
RH
1240 macro_entry *macro;
1241 sb line_sb;
1242
5e75c3ab 1243 if (! is_name_beginner (*line)
252b5132
RH
1244 && (! macro_mri || *line != '.'))
1245 return 0;
1246
1247 s = line + 1;
5e75c3ab
JB
1248 while (is_part_of_name (*s))
1249 ++s;
1250 if (is_name_ender (*s))
252b5132
RH
1251 ++s;
1252
1253 copy = (char *) alloca (s - line + 1);
1254 memcpy (copy, line, s - line);
1255 copy[s - line] = '\0';
91d6fa6a
NC
1256 for (cls = copy; *cls != '\0'; cls ++)
1257 *cls = TOLOWER (*cls);
252b5132
RH
1258
1259 macro = (macro_entry *) hash_find (macro_hash, copy);
1260
1261 if (macro == NULL)
1262 return 0;
1263
1264 /* Wrap the line up in an sb. */
1265 sb_new (&line_sb);
1266 while (*s != '\0' && *s != '\n' && *s != '\r')
1267 sb_add_char (&line_sb, *s++);
1268
1269 sb_new (expand);
fea17916 1270 *error = macro_expand (0, &line_sb, macro, expand);
252b5132
RH
1271
1272 sb_kill (&line_sb);
1273
29f8404c 1274 /* Export the macro information if requested. */
9f10757c
TW
1275 if (info)
1276 *info = macro;
1277
252b5132
RH
1278 return 1;
1279}
1280
1281/* Delete a macro. */
1282
1283void
254d758c 1284delete_macro (const char *name)
252b5132 1285{
e6ca91be
JB
1286 char *copy;
1287 size_t i, len;
1288 macro_entry *macro;
1289
1290 len = strlen (name);
1291 copy = (char *) alloca (len + 1);
1292 for (i = 0; i < len; ++i)
1293 copy[i] = TOLOWER (name[i]);
1294 copy[i] = '\0';
1295
818236e5
AM
1296 /* We can only ask hash_delete to free memory if we are deleting
1297 macros in reverse order to their definition.
1298 So just clear out the entry. */
1e9cc1c2 1299 if ((macro = (macro_entry *) hash_find (macro_hash, copy)) != NULL)
e6ca91be
JB
1300 {
1301 hash_jam (macro_hash, copy, NULL);
1302 free_macro (macro);
1303 }
1304 else
1305 as_warn (_("Attempt to purge non-existant macro `%s'"), copy);
252b5132
RH
1306}
1307
1308/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a
1309 combined macro definition and execution. This returns NULL on
1310 success, or an error message otherwise. */
1311
1312const char *
39a45edc 1313expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
252b5132 1314{
252b5132
RH
1315 sb sub;
1316 formal_entry f;
1317 struct hash_control *h;
1318 const char *err;
1319
252b5132
RH
1320 idx = sb_skip_white (idx, in);
1321
1322 sb_new (&sub);
ca3bc58f 1323 if (! buffer_and_nest (NULL, "ENDR", &sub, get_line))
252b5132 1324 return _("unexpected end of file in irp or irpc");
29f8404c 1325
252b5132
RH
1326 sb_new (&f.name);
1327 sb_new (&f.def);
1328 sb_new (&f.actual);
1329
1330 idx = get_token (idx, in, &f.name);
1331 if (f.name.len == 0)
1332 return _("missing model parameter");
1333
1334 h = hash_new ();
1335 err = hash_jam (h, sb_terminate (&f.name), &f);
1336 if (err != NULL)
1337 return err;
1338
1339 f.index = 1;
1340 f.next = NULL;
6eaeac8a 1341 f.type = FORMAL_OPTIONAL;
252b5132
RH
1342
1343 sb_reset (out);
1344
1345 idx = sb_skip_comma (idx, in);
fea17916 1346 if (idx >= in->len)
252b5132
RH
1347 {
1348 /* Expand once with a null string. */
fea17916 1349 err = macro_expand_body (&sub, out, &f, h, 0);
252b5132
RH
1350 }
1351 else
1352 {
465e5617
NC
1353 bfd_boolean in_quotes = FALSE;
1354
252b5132 1355 if (irpc && in->ptr[idx] == '"')
465e5617
NC
1356 {
1357 in_quotes = TRUE;
1358 ++idx;
1359 }
1360
fea17916 1361 while (idx < in->len)
252b5132
RH
1362 {
1363 if (!irpc)
be03cc84 1364 idx = get_any_string (idx, in, &f.actual);
252b5132
RH
1365 else
1366 {
1367 if (in->ptr[idx] == '"')
1368 {
39a45edc 1369 size_t nxt;
252b5132 1370
465e5617
NC
1371 if (irpc)
1372 in_quotes = ! in_quotes;
4c665b71 1373
252b5132 1374 nxt = sb_skip_white (idx + 1, in);
fea17916 1375 if (nxt >= in->len)
252b5132
RH
1376 {
1377 idx = nxt;
1378 break;
1379 }
1380 }
1381 sb_reset (&f.actual);
1382 sb_add_char (&f.actual, in->ptr[idx]);
1383 ++idx;
1384 }
465e5617 1385
fea17916 1386 err = macro_expand_body (&sub, out, &f, h, 0);
252b5132 1387 if (err != NULL)
02ddf156 1388 break;
252b5132
RH
1389 if (!irpc)
1390 idx = sb_skip_comma (idx, in);
465e5617 1391 else if (! in_quotes)
252b5132
RH
1392 idx = sb_skip_white (idx, in);
1393 }
1394 }
1395
1396 hash_die (h);
6eaeac8a
JB
1397 sb_kill (&f.actual);
1398 sb_kill (&f.def);
1399 sb_kill (&f.name);
252b5132
RH
1400 sb_kill (&sub);
1401
02ddf156 1402 return err;
252b5132 1403}
This page took 0.717575 seconds and 4 git commands to generate.