Line | Count | Source |
1 | | /* misc - miscellaneous flex routines */ |
2 | | |
3 | | /* Copyright (c) 1990 The Regents of the University of California. */ |
4 | | /* All rights reserved. */ |
5 | | |
6 | | /* This code is derived from software contributed to Berkeley by */ |
7 | | /* Vern Paxson. */ |
8 | | |
9 | | /* The United States Government has rights in this work pursuant */ |
10 | | /* to contract no. DE-AC03-76SF00098 between the United States */ |
11 | | /* Department of Energy and the University of California. */ |
12 | | |
13 | | /* This file is part of flex. */ |
14 | | |
15 | | /* Redistribution and use in source and binary forms, with or without */ |
16 | | /* modification, are permitted provided that the following conditions */ |
17 | | /* are met: */ |
18 | | |
19 | | /* 1. Redistributions of source code must retain the above copyright */ |
20 | | /* notice, this list of conditions and the following disclaimer. */ |
21 | | /* 2. Redistributions in binary form must reproduce the above copyright */ |
22 | | /* notice, this list of conditions and the following disclaimer in the */ |
23 | | /* documentation and/or other materials provided with the distribution. */ |
24 | | |
25 | | /* Neither the name of the University nor the names of its contributors */ |
26 | | /* may be used to endorse or promote products derived from this software */ |
27 | | /* without specific prior written permission. */ |
28 | | |
29 | | /* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */ |
30 | | /* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */ |
31 | | /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ |
32 | | /* PURPOSE. */ |
33 | | #include "flexdef.h" |
34 | | #include "tables.h" |
35 | | |
36 | | /* Append "new_text" to the running buffer. */ |
37 | | void add_action (const char *new_text) |
38 | 744 | { |
39 | 744 | int len = (int) strlen (new_text); |
40 | | |
41 | 744 | while (len + action_index >= action_size - 10 /* slop */ ) { |
42 | |
|
43 | 0 | if (action_size > INT_MAX / 2) |
44 | | /* Increase just a little, to try to avoid overflow |
45 | | * on 16-bit machines. |
46 | | */ |
47 | 0 | action_size += action_size / 8; |
48 | 0 | else |
49 | 0 | action_size = action_size * 2; |
50 | |
|
51 | 0 | action_array = |
52 | 0 | reallocate_character_array (action_array, |
53 | 0 | action_size); |
54 | 0 | } |
55 | | |
56 | 744 | strcpy (&action_array[action_index], new_text); |
57 | | |
58 | 744 | action_index += len; |
59 | 744 | } |
60 | | |
61 | | |
62 | | /* allocate_array - allocate memory for an integer array of the given size */ |
63 | | |
64 | | void *allocate_array (int size, size_t element_size) |
65 | 19.8k | { |
66 | 19.8k | return reallocate_array(NULL, size, element_size); |
67 | 19.8k | } |
68 | | |
69 | | |
70 | | /* all_lower - true if a string is all lower-case */ |
71 | | |
72 | | int all_lower (char *str) |
73 | 0 | { |
74 | 0 | while (*str) { |
75 | 0 | if (!isascii ((unsigned char) * str) || !islower ((unsigned char) * str)) |
76 | 0 | return 0; |
77 | 0 | ++str; |
78 | 0 | } |
79 | | |
80 | 0 | return 1; |
81 | 0 | } |
82 | | |
83 | | |
84 | | /* all_upper - true if a string is all upper-case */ |
85 | | |
86 | | int all_upper (char *str) |
87 | 0 | { |
88 | 0 | while (*str) { |
89 | 0 | if (!isascii ((unsigned char) * str) || !isupper ((unsigned char) * str)) |
90 | 0 | return 0; |
91 | 0 | ++str; |
92 | 0 | } |
93 | | |
94 | 0 | return 1; |
95 | 0 | } |
96 | | |
97 | | |
98 | | /* intcmp - compares two integers for use by qsort. */ |
99 | | |
100 | | int intcmp (const void *a, const void *b) |
101 | 0 | { |
102 | 0 | return *(const int *) a - *(const int *) b; |
103 | 0 | } |
104 | | |
105 | | |
106 | | /* check_char - checks a character to make sure it's within the range |
107 | | * we're expecting. If not, generates fatal error message |
108 | | * and exits. |
109 | | */ |
110 | | |
111 | | void check_char (int c) |
112 | 0 | { |
113 | 0 | if (c >= CSIZE) |
114 | 0 | lerr (_("bad character '%s' detected in check_char()"), |
115 | 0 | readable_form (c)); |
116 | |
|
117 | 0 | if (c >= ctrl.csize) |
118 | 0 | lerr (_ |
119 | 0 | ("scanner requires -8 flag to use the character %s"), |
120 | 0 | readable_form (c)); |
121 | 0 | } |
122 | | |
123 | | |
124 | | |
125 | | /* clower - replace upper-case letter to lower-case */ |
126 | | |
127 | | unsigned char clower (int c) |
128 | 0 | { |
129 | 0 | return (unsigned char) ((isascii (c) && isupper (c)) ? tolower (c) : c); |
130 | 0 | } |
131 | | |
132 | | |
133 | | char *xstrdup(const char *s) |
134 | 605 | { |
135 | 605 | char *s2; |
136 | | |
137 | 605 | if ((s2 = strdup(s)) == NULL) |
138 | 0 | flexfatal (_("memory allocation failure in xstrdup()")); |
139 | | |
140 | 605 | return s2; |
141 | 605 | } |
142 | | |
143 | | |
144 | | /* cclcmp - compares two characters for use by qsort with '\0' sorting last. */ |
145 | | |
146 | | int cclcmp (const void *a, const void *b) |
147 | 0 | { |
148 | 0 | if (!*(const unsigned char *) a) |
149 | 0 | return 1; |
150 | 0 | else |
151 | 0 | if (!*(const unsigned char *) b) |
152 | 0 | return - 1; |
153 | 0 | else |
154 | 0 | return *(const unsigned char *) a - *(const unsigned char *) b; |
155 | 0 | } |
156 | | |
157 | | |
158 | | /* dataend - finish up a block of data declarations */ |
159 | | |
160 | | void dataend (const char *endit) |
161 | 0 | { |
162 | | /* short circuit any output */ |
163 | 0 | if (gentables) { |
164 | |
|
165 | 0 | if (datapos > 0) |
166 | 0 | dataflush (); |
167 | | |
168 | | /* add terminator for initialization; { for vi */ |
169 | 0 | if (endit) |
170 | 0 | outn (endit); |
171 | 0 | } |
172 | 0 | dataline = 0; |
173 | 0 | datapos = 0; |
174 | 0 | } |
175 | | |
176 | | |
177 | | /* dataflush - flush generated data statements */ |
178 | | |
179 | | void dataflush (void) |
180 | 0 | { |
181 | 0 | assert (gentables); |
182 | |
|
183 | 0 | if (datapos > 0) |
184 | 0 | outc ('\n'); |
185 | |
|
186 | 0 | if (++dataline >= NUMDATALINES) { |
187 | | /* Put out a blank line so that the table is grouped into |
188 | | * large blocks that enable the user to find elements easily. |
189 | | */ |
190 | 0 | outc ('\n'); |
191 | 0 | dataline = 0; |
192 | 0 | } |
193 | | |
194 | | /* Reset the number of characters written on the current line. */ |
195 | 0 | datapos = 0; |
196 | 0 | } |
197 | | |
198 | | |
199 | | /* flexerror - report an error message and terminate */ |
200 | | |
201 | | void flexerror (const char *msg) |
202 | 0 | { |
203 | 0 | fprintf (stderr, "%s: %s\n", program_name, msg); |
204 | 0 | flexend (1); |
205 | 0 | } |
206 | | |
207 | | |
208 | | /* flexfatal - report a fatal error message and terminate */ |
209 | | |
210 | | void flexfatal (const char *msg) |
211 | 0 | { |
212 | 0 | fprintf (stderr, _("%s: fatal internal error, %s\n"), |
213 | 0 | program_name, msg); |
214 | 0 | FLEX_EXIT (1); |
215 | 0 | } |
216 | | |
217 | | |
218 | | /* lerr - report an error message */ |
219 | | |
220 | | void lerr (const char *msg, ...) |
221 | 0 | { |
222 | 0 | char errmsg[MAXLINE]; |
223 | 0 | va_list args; |
224 | |
|
225 | 0 | va_start(args, msg); |
226 | 0 | vsnprintf (errmsg, sizeof(errmsg), msg, args); |
227 | 0 | va_end(args); |
228 | 0 | flexerror (errmsg); |
229 | 0 | } |
230 | | |
231 | | |
232 | | /* lerr_fatal - as lerr, but call flexfatal */ |
233 | | |
234 | | void lerr_fatal (const char *msg, ...) |
235 | 0 | { |
236 | 0 | char errmsg[MAXLINE]; |
237 | 0 | va_list args; |
238 | 0 | va_start(args, msg); |
239 | |
|
240 | 0 | vsnprintf (errmsg, sizeof(errmsg), msg, args); |
241 | 0 | va_end(args); |
242 | 0 | flexfatal (errmsg); |
243 | 0 | } |
244 | | |
245 | | |
246 | | /* line_directive_out - spit out a "#line" statement or equivalent */ |
247 | | void line_directive_out (FILE *output_file, char *path, int linenum) |
248 | 701 | { |
249 | 701 | char *trace_fmt = "m4_ifdef([[M4_HOOK_TRACE_LINE_FORMAT]], [[M4_HOOK_TRACE_LINE_FORMAT([[%d]], [[%s]])]])"; |
250 | 701 | char directive[MAXLINE*2], filename[MAXLINE]; |
251 | 701 | char *s1, *s2, *s3; |
252 | | |
253 | 701 | if (!ctrl.gen_line_dirs) |
254 | 701 | return; |
255 | | |
256 | 0 | s1 = (path != NULL) ? path : "M4_YY_OUTFILE_NAME"; |
257 | |
|
258 | 0 | if ((path != NULL) && !s1) |
259 | 0 | s1 = "<stdin>"; |
260 | | |
261 | 0 | s2 = filename; |
262 | 0 | s3 = &filename[sizeof (filename) - 2]; |
263 | |
|
264 | 0 | while (s2 < s3 && *s1) { |
265 | 0 | if (*s1 == '\\' || *s1 == '"') |
266 | | /* Escape the '\' or '"' */ |
267 | 0 | *s2++ = '\\'; |
268 | |
|
269 | 0 | *s2++ = *s1++; |
270 | 0 | } |
271 | |
|
272 | 0 | *s2 = '\0'; |
273 | |
|
274 | 0 | if (path != NULL) |
275 | 0 | snprintf (directive, sizeof(directive), trace_fmt, linenum, filename); |
276 | 0 | else { |
277 | 0 | snprintf (directive, sizeof(directive), trace_fmt, 0, filename); |
278 | 0 | } |
279 | | |
280 | | /* If output_file is nil then we should put the directive in |
281 | | * the accumulated actions. |
282 | | */ |
283 | 0 | if (output_file) { |
284 | 0 | fputs (directive, output_file); |
285 | 0 | } |
286 | 0 | else |
287 | 0 | add_action (directive); |
288 | 0 | } |
289 | | |
290 | | |
291 | | /* mark_defs1 - mark the current position in the action array as |
292 | | * representing where the user's section 1 definitions end |
293 | | * and the prolog begins |
294 | | */ |
295 | | void mark_defs1 (void) |
296 | 1 | { |
297 | 1 | defs1_offset = 0; |
298 | 1 | action_array[action_index++] = '\0'; |
299 | 1 | action_offset = prolog_offset = action_index; |
300 | 1 | action_array[action_index] = '\0'; |
301 | 1 | } |
302 | | |
303 | | |
304 | | /* mark_prolog - mark the current position in the action array as |
305 | | * representing the end of the action prolog |
306 | | */ |
307 | | void mark_prolog (void) |
308 | 2 | { |
309 | 2 | action_array[action_index++] = '\0'; |
310 | 2 | action_offset = action_index; |
311 | 2 | action_array[action_index] = '\0'; |
312 | 2 | } |
313 | | |
314 | | |
315 | | /* mk2data - generate a data statement for a two-dimensional array |
316 | | * |
317 | | * Generates a data statement initializing the current 2-D array to "value". |
318 | | */ |
319 | | void mk2data (int value) |
320 | 0 | { |
321 | | /* short circuit any output */ |
322 | 0 | if (!gentables) |
323 | 0 | return; |
324 | | |
325 | 0 | if (datapos >= NUMDATAITEMS) { |
326 | 0 | outc (','); |
327 | 0 | dataflush (); |
328 | 0 | } |
329 | |
|
330 | 0 | if (datapos == 0) |
331 | | /* Indent. */ |
332 | 0 | out (" "); |
333 | | |
334 | 0 | else |
335 | 0 | outc (','); |
336 | |
|
337 | 0 | ++datapos; |
338 | |
|
339 | 0 | out_dec ("%5d", value); |
340 | 0 | } |
341 | | |
342 | | |
343 | | /* mkdata - generate a data statement |
344 | | * |
345 | | * Generates a data statement initializing the current array element to |
346 | | * "value". |
347 | | */ |
348 | | void mkdata (int value) |
349 | 0 | { |
350 | | /* short circuit any output */ |
351 | 0 | if (!gentables) |
352 | 0 | return; |
353 | | |
354 | 0 | if (datapos >= NUMDATAITEMS) { |
355 | 0 | outc (','); |
356 | 0 | dataflush (); |
357 | 0 | } |
358 | |
|
359 | 0 | if (datapos == 0) |
360 | | /* Indent. */ |
361 | 0 | out (" "); |
362 | 0 | else |
363 | 0 | outc (','); |
364 | 0 | ++datapos; |
365 | |
|
366 | 0 | out_dec ("%5d", value); |
367 | 0 | } |
368 | | |
369 | | |
370 | | /* myctoi - return the integer represented by a string of digits */ |
371 | | |
372 | | int myctoi (const char *array) |
373 | 0 | { |
374 | 0 | int val = 0; |
375 | |
|
376 | 0 | (void) sscanf (array, "%d", &val); |
377 | |
|
378 | 0 | return val; |
379 | 0 | } |
380 | | |
381 | | |
382 | | /* myesc - return character corresponding to escape sequence */ |
383 | | |
384 | | unsigned char myesc (unsigned char array[]) |
385 | 1 | { |
386 | 1 | unsigned char c, esc_char; |
387 | | |
388 | 1 | switch (array[1]) { |
389 | 0 | case 'b': |
390 | 0 | return '\b'; |
391 | 0 | case 'f': |
392 | 0 | return '\f'; |
393 | 0 | case 'n': |
394 | 0 | return '\n'; |
395 | 0 | case 'r': |
396 | 0 | return '\r'; |
397 | 0 | case 't': |
398 | 0 | return '\t'; |
399 | 0 | case 'a': |
400 | 0 | return '\a'; |
401 | 0 | case 'v': |
402 | 0 | return '\v'; |
403 | 0 | case '0': |
404 | 0 | case '1': |
405 | 0 | case '2': |
406 | 0 | case '3': |
407 | 0 | case '4': |
408 | 0 | case '5': |
409 | 0 | case '6': |
410 | 0 | case '7': |
411 | 0 | { /* \<octal> */ |
412 | 0 | int sptr = 1; |
413 | |
|
414 | 0 | while (sptr <= 3 && |
415 | 0 | array[sptr] >= '0' && array[sptr] <= '7') { |
416 | 0 | ++sptr; |
417 | 0 | } |
418 | |
|
419 | 0 | c = array[sptr]; |
420 | 0 | array[sptr] = '\0'; |
421 | |
|
422 | 0 | esc_char = (unsigned char) strtoul (array + 1, NULL, 8); |
423 | |
|
424 | 0 | array[sptr] = c; |
425 | |
|
426 | 0 | return esc_char; |
427 | 0 | } |
428 | | |
429 | 0 | case 'x': |
430 | 0 | { /* \x<hex> */ |
431 | 0 | int sptr = 2; |
432 | |
|
433 | 0 | while (sptr <= 3 && isxdigit (array[sptr])) { |
434 | | /* Don't increment inside loop control |
435 | | * because if isxdigit() is a macro it might |
436 | | * expand into multiple increments ... |
437 | | */ |
438 | 0 | ++sptr; |
439 | 0 | } |
440 | |
|
441 | 0 | c = array[sptr]; |
442 | 0 | array[sptr] = '\0'; |
443 | |
|
444 | 0 | esc_char = (unsigned char) strtoul (array + 2, NULL, 16); |
445 | |
|
446 | 0 | array[sptr] = c; |
447 | |
|
448 | 0 | return esc_char; |
449 | 0 | } |
450 | | |
451 | 1 | default: |
452 | 1 | return array[1]; |
453 | 1 | } |
454 | 1 | } |
455 | | |
456 | | |
457 | | /* out - various flavors of outputting a (possibly formatted) string for the |
458 | | * generated scanner, keeping track of the line count. |
459 | | */ |
460 | | |
461 | | void out (const char *str) |
462 | 0 | { |
463 | 0 | fputs (str, stdout); |
464 | 0 | } |
465 | | |
466 | | void out_dec (const char *fmt, int n) |
467 | 0 | { |
468 | 0 | fprintf (stdout, fmt, n); |
469 | 0 | } |
470 | | |
471 | | void out_dec2 (const char *fmt, int n1, int n2) |
472 | 0 | { |
473 | 0 | fprintf (stdout, fmt, n1, n2); |
474 | 0 | } |
475 | | |
476 | | void out_hex (const char *fmt, unsigned int x) |
477 | 0 | { |
478 | 0 | fprintf (stdout, fmt, x); |
479 | 0 | } |
480 | | |
481 | | void out_str (const char *fmt, const char str[]) |
482 | 0 | { |
483 | 0 | fprintf (stdout,fmt, str); |
484 | 0 | } |
485 | | |
486 | | void out_str_dec (const char *fmt, const char str[], int n) |
487 | 0 | { |
488 | 0 | fprintf (stdout,fmt, str, n); |
489 | 0 | } |
490 | | |
491 | | void outc (int c) |
492 | 0 | { |
493 | 0 | fputc (c, stdout); |
494 | 0 | } |
495 | | |
496 | | void outn (const char *str) |
497 | 0 | { |
498 | 0 | fputs (str,stdout); |
499 | 0 | fputc('\n',stdout); |
500 | 0 | } |
501 | | |
502 | | /** Print "m4_define( [[def]], [[val]])m4_dnl\n". |
503 | | * @param def The m4 symbol to define. |
504 | | * @param val The definition; may be NULL. |
505 | | */ |
506 | | void out_m4_define (const char* def, const char* val) |
507 | 0 | { |
508 | 0 | const char * fmt = "m4_define( [[%s]], [[%s]])m4_dnl\n"; |
509 | 0 | fprintf(stdout, fmt, def, val?val:""); |
510 | 0 | } |
511 | | |
512 | | |
513 | | /* readable_form - return the the human-readable form of a character |
514 | | * |
515 | | * The returned string is in static storage. |
516 | | */ |
517 | | |
518 | | char *readable_form (int c) |
519 | 0 | { |
520 | 0 | static char rform[20]; |
521 | |
|
522 | 0 | if ((c >= 0 && c < 32) || c >= 127) { |
523 | 0 | switch (c) { |
524 | 0 | case '\b': |
525 | 0 | return "\\b"; |
526 | 0 | case '\f': |
527 | 0 | return "\\f"; |
528 | 0 | case '\n': |
529 | 0 | return "\\n"; |
530 | 0 | case '\r': |
531 | 0 | return "\\r"; |
532 | 0 | case '\t': |
533 | 0 | return "\\t"; |
534 | 0 | case '\a': |
535 | 0 | return "\\a"; |
536 | 0 | case '\v': |
537 | 0 | return "\\v"; |
538 | 0 | default: |
539 | 0 | if(env.trace_hex) |
540 | 0 | snprintf (rform, sizeof(rform), "\\x%.2x", (unsigned int) c); |
541 | 0 | else |
542 | 0 | snprintf (rform, sizeof(rform), "\\%.3o", (unsigned int) c); |
543 | 0 | return rform; |
544 | 0 | } |
545 | 0 | } |
546 | | |
547 | 0 | else if (c == ' ') |
548 | 0 | return "' '"; |
549 | | |
550 | 0 | else { |
551 | 0 | rform[0] = (char) c; |
552 | 0 | rform[1] = '\0'; |
553 | |
|
554 | 0 | return rform; |
555 | 0 | } |
556 | 0 | } |
557 | | |
558 | | |
559 | | /* reallocate_array - increase the size of a dynamic array */ |
560 | | |
561 | | void *reallocate_array (void *array, int size, size_t element_size) |
562 | 19.8k | { |
563 | 19.8k | void *new_array; |
564 | | #ifdef HAVE_REALLOCARR |
565 | | new_array = array; |
566 | | if (reallocarr(&new_array, (size_t) size, element_size)) { |
567 | | flexfatal ((array) ? |
568 | | _("attempt to increase array size failed") : |
569 | | /* Function name is allocate_array() because of |
570 | | * compatibility (for translations): */ |
571 | | _("memory allocation failed in allocate_array()")); |
572 | | } |
573 | | #else |
574 | 19.8k | # ifdef HAVE_REALLOCARRAY |
575 | 19.8k | new_array = reallocarray(array, (size_t) size, element_size); |
576 | | # else |
577 | | /* Do manual overflow detection */ |
578 | | size_t num_bytes = (size_t) size * element_size; |
579 | | new_array = (size && SIZE_MAX / (size_t) size < element_size) ? NULL : |
580 | | realloc(array, num_bytes); |
581 | | # endif |
582 | 19.8k | if (!new_array) { |
583 | 0 | flexfatal ((array) ? |
584 | 0 | _("attempt to increase array size failed") : |
585 | | /* Function name is allocate_array() because of |
586 | | * compatibility (for translations): */ |
587 | 0 | _("memory allocation failed in allocate_array()")); |
588 | 0 | } |
589 | 19.8k | #endif |
590 | 19.8k | return new_array; |
591 | 19.8k | } |
592 | | |
593 | | |
594 | | /* transition_struct_out - output a yy_trans_info structure |
595 | | * |
596 | | * outputs the yy_trans_info structure with the two elements, element_v and |
597 | | * element_n. Formats the output with spaces and carriage returns. |
598 | | */ |
599 | | |
600 | | void transition_struct_out (int element_v, int element_n) |
601 | 0 | { |
602 | | |
603 | | /* short circuit any output */ |
604 | 0 | if (!gentables) |
605 | 0 | return; |
606 | | |
607 | 0 | out_dec2 ("M4_HOOK_TABLE_OPENER[[%4d]],[[%4d]]M4_HOOK_TABLE_CONTINUE", element_v, element_n); |
608 | 0 | outc ('\n'); |
609 | |
|
610 | 0 | datapos += TRANS_STRUCT_PRINT_LENGTH; |
611 | |
|
612 | 0 | if (datapos >= 79 - TRANS_STRUCT_PRINT_LENGTH) { |
613 | 0 | outc ('\n'); |
614 | |
|
615 | 0 | if (++dataline % 10 == 0) |
616 | 0 | outc ('\n'); |
617 | |
|
618 | 0 | datapos = 0; |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | |
623 | | /* The following is only needed when building flex's parser using certain |
624 | | * broken versions of bison. |
625 | | * |
626 | | * XXX: this is should go soon |
627 | | */ |
628 | | void *yy_flex_xmalloc (int size) |
629 | 0 | { |
630 | 0 | void *result; |
631 | |
|
632 | 0 | result = malloc((size_t) size); |
633 | 0 | if (!result) |
634 | 0 | flexfatal (_ |
635 | 0 | ("memory allocation failed in yy_flex_xmalloc()")); |
636 | |
|
637 | 0 | return result; |
638 | 0 | } |
639 | | |
640 | | |
641 | | /* Remove all '\n' and '\r' characters, if any, from the end of str. |
642 | | * str can be any null-terminated string, or NULL. |
643 | | * returns str. */ |
644 | | char *chomp (char *str) |
645 | 0 | { |
646 | 0 | char *p = str; |
647 | |
|
648 | 0 | if (!str || !*str) /* s is null or empty string */ |
649 | 0 | return str; |
650 | | |
651 | | /* find end of string minus one */ |
652 | 0 | while (*p) |
653 | 0 | ++p; |
654 | 0 | --p; |
655 | | |
656 | | /* eat newlines */ |
657 | 0 | while (p >= str && (*p == '\r' || *p == '\n')) |
658 | 0 | *p-- = 0; |
659 | 0 | return str; |
660 | 0 | } |
661 | | |
662 | | void comment(const char *txt) |
663 | 0 | { |
664 | 0 | char buf[MAXLINE]; |
665 | 0 | bool eol; |
666 | |
|
667 | 0 | strncpy(buf, txt, MAXLINE-1); |
668 | 0 | eol = buf[strlen(buf)-1] == '\n'; |
669 | |
|
670 | 0 | if (eol) |
671 | 0 | buf[strlen(buf)-1] = '\0'; |
672 | 0 | out_str("M4_HOOK_COMMENT_OPEN [[%s]] M4_HOOK_COMMENT_CLOSE", buf); |
673 | 0 | if (eol) |
674 | 0 | outc ('\n'); |
675 | 0 | } |
676 | | |
677 | | |