/* mp4h -- A macro processor for HTML documents Copyright 2000-2002, Denis Barbier All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is a work based on GNU m4 version 1.4n. Below is the original copyright. */ /* GNU m4 -- A simple macro processor Copyright (C) 1989, 90, 91, 92, 93, 94, 98 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Global function useful for builtin.c and loadable modules. */ #define MP4H_MODULE #include "mp4h.h" #undef MP4H_MODULE static const char * skip_space __P ((const char *)); /* Stack for predefined attributes. */ static var_stack *tag_attr = NULL; /*------------------------------------------------------------------------. | Give friendly warnings if a builtin macro is passed an inappropriate | | number of arguments. NAME is macro name for messages, ARGC is actual | | number of arguments, MIN is the minimum number of acceptable arguments, | | negative if not applicable, MAX is the maximum number, negative if not | | applicable. | `------------------------------------------------------------------------*/ boolean bad_argc (token_data *name, int argc, int min, int max) { boolean isbad = FALSE; if (min > 0 && argc < min) { if (!suppress_warnings) MP4HERROR ((warning_status, 0, _("Warning:%s:%d: Too few arguments to built-in `%s'"), CURRENT_FILE_LINE, TOKEN_DATA_TEXT (name))); isbad = TRUE; } else if (max > 0 && argc > max && !suppress_warnings) { MP4HERROR ((warning_status, 0, _("Warning:%s:%d: Excess arguments to built-in `%s' ignored"), CURRENT_FILE_LINE, TOKEN_DATA_TEXT (name))); } return isbad; } /*--------------------------------------------------------------------------. | The function numeric_arg () converts ARG to an int pointed to by VALUEP. | | If the conversion fails, print error message for macro MACRO. Return | | TRUE iff conversion succeeds. | `--------------------------------------------------------------------------*/ static const char * skip_space (const char *arg) { while (IS_SPACE (*arg)) arg++; return arg; } boolean numeric_arg (token_data *macro, const char *arg, boolean warn, int *valuep) { char *endp; if (*arg == 0 || (*valuep = strtol (skip_space (arg), &endp, 10), *skip_space (endp) != 0)) { if (warn) MP4HERROR ((warning_status, 0, _("Warning:%s:%d: Argument `%s' non-numeric in the <%s> tag"), CURRENT_FILE_LINE, arg, TOKEN_DATA_TEXT (macro))); return FALSE; } return TRUE; } /*----------------------------------------------------------------------. | Format an int VAL, and stuff it into an obstack OBS. Used for macros | | expanding to numbers. | `----------------------------------------------------------------------*/ void shipout_int (struct obstack *obs, int val) { char buf[128]; sprintf (buf, "%d", val); obstack_grow (obs, buf, strlen (buf)); } /*---------------------. | Idem, for long int. | `---------------------*/ void shipout_long (struct obstack *obs, long val) { char buf[128]; sprintf (buf, "%ld", val); obstack_grow (obs, buf, strlen (buf)); } /*----------------------------------------------------------------. | The shipout_string is used when string length can be computed. | `----------------------------------------------------------------*/ void shipout_string (struct obstack *obs, const char *s, int len) { if (s == NULL) s = ""; if (len == 0) len = strlen (s); obstack_grow (obs, s, len); } /*----------------------------------------------------------. | Print ARGC arguments from the table ARGV to obstack OBS, | | separated by SEP. | `----------------------------------------------------------*/ void dump_args (struct obstack *obs, int argc, token_data **argv, const char *sep) { int i; for (i = 1; i < argc; i++) { if (i > 1 && sep) obstack_grow (obs, sep, strlen (sep)); obstack_1grow (obs, CHAR_BGROUP); /* Remove surrounding double quotes */ if (*ARG (i) == '"' && LAST_CHAR (ARG (i)) == '"') obstack_grow (obs, ARG (i) + 1, strlen (ARG (i)) - 2); else obstack_grow (obs, ARG (i), strlen (ARG (i))); obstack_1grow (obs, CHAR_EGROUP); } } /*--------------------------------------------------------------------------. | The function predefined_attribute () reads attributes and returns the | | value associated with the key named ``key''. | `--------------------------------------------------------------------------*/ const char * predefined_attribute (const char *key, int *ptr_argc, token_data **argv, boolean lowercase) { var_stack *next; char *cp, *sp, *lower; int i, j, special_chars; boolean found = FALSE; i = 1; while (i<*ptr_argc) { special_chars = 0; sp = TOKEN_DATA_TEXT (argv[i]); while (IS_GROUP (*sp)) { sp++; special_chars++; } cp = strchr (sp, '='); if ((cp == NULL && strcasecmp (sp, key) == 0) || (cp != NULL && strncasecmp (sp, key, strlen (key)) == 0 && *(sp + strlen (key)) == '=')) { found = TRUE; next = (var_stack *) xmalloc (sizeof (var_stack)); next->prev = tag_attr; if (cp) { next->text = (char *) xmalloc (special_chars + strlen (cp+1) + 1); if (special_chars) strncpy (next->text, TOKEN_DATA_TEXT (argv[i]), special_chars); strcpy (next->text+special_chars, cp+1); } else next->text = xstrdup (key); tag_attr = next; if (lowercase) for (lower=tag_attr->text; *lower != '\0'; lower++) *lower = tolower (*lower); /* remove this attribute from argv[]. */ for (j=i+1; j<=*ptr_argc; j++) argv[j-1] = argv[j]; (*ptr_argc)--; } i++; } return (found ? tag_attr->text : NULL ); } /*--------------------------------------------------------------------------. | Clear stack containing predefined attributes. This function is called | | after macro has been evaluated. | `--------------------------------------------------------------------------*/ void clear_tag_attr (void) { var_stack *pa; while (tag_attr) { pa = tag_attr->prev; xfree ((voidstar) tag_attr->text); xfree ((voidstar) tag_attr); tag_attr = pa; } }