/* * optstr.c * * Copyright (C) Tilmann Bitterberg 2003 * * Description: A general purpose option string parser * * Usage: see optstr.h, please * * This file is part of transcode, a video stream processing tool * * transcode 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. * * transcode 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 GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* for vsscanf */ #ifdef HAVE_VSSCANF # define _GNU_SOURCE #endif #include #include #include #include #include "optstr.h" #include "libtc.h" const char* optstr_lookup(const char *haystack, const char *needle) { const char *ch = haystack; int found = 0; size_t len = strlen(needle); while (!found) { ch = strstr(ch, needle); /* not in string */ if (!ch) { break; } /* do we want this hit? ie is it exact? */ if (ch[len] == '\0' || ch[len] == '=' || ch[len] == ARG_SEP) { found = 1; } else { /* go a little further */ ch++; } } return ch; } int optstr_get(const char *options, const char *name, const char *fmt, ...) { va_list ap; /* points to each unnamed arg in turn */ int num_args = 0, n = 0; size_t pos, fmt_len = strlen(fmt); const char *ch = NULL; #ifndef HAVE_VSSCANF void *temp[ARG_MAXIMUM]; #endif ch = optstr_lookup(options, name); if (!ch) { return -1; } /* name IS in options */ /* Find how many arguments we expect */ for (pos = 0; pos < fmt_len; pos++) { if (fmt[pos] == '%') { ++num_args; /* is this one quoted with '%%' */ if (pos + 1 < fmt_len && fmt[pos + 1] == '%') { --num_args; ++pos; } } } #ifndef HAVE_VSSCANF if (num_args > ARG_MAXIMUM) { fprintf (stderr, "(%s:%d) Internal Overflow; redefine ARG_MAXIMUM (%d) to something higher\n", __FILE__, __LINE__, ARG_MAXIMUM); return -2; } #endif n = num_args; /* Bool argument */ if (num_args <= 0) { return 0; } /* skip the `=' (if it is one) */ ch += strlen( name ); if( *ch == '=' ) ch++; if( !*ch ) return 0; va_start(ap, fmt); #ifndef HAVE_VSSCANF while (--n >= 0) { temp[num_args - n - 1] = va_arg(ap, void *); } n = sscanf(ch, fmt, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7], temp[8], temp[9], temp[10], temp[11], temp[12], temp[13], temp[14], temp[15]); #else /* this would be very nice instead of the above, * but it does not seem portable */ n = vsscanf(ch, fmt, ap); #endif va_end(ap); return n; } static int optstr_is_string_arg(const char *fmt) { if (!fmt) { return 0; } if (!strlen(fmt)) { return 0; } if (strchr(fmt, 's')) { return 1; } if (strchr(fmt, '[') && strchr(fmt, ']')) { return 1; } return 0; } int optstr_filter_desc(char *buf, const char *filter_name, const char *filter_comment, const char *filter_version, const char *filter_author, const char *capabilities, const char *frames_needed) { int len = strlen(buf); if (tc_snprintf(buf + len, ARG_CONFIG_LEN - len, "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n", filter_name,filter_comment,filter_version, filter_author, capabilities, frames_needed) <= 0) { return 1; } return 0; } int optstr_frames_needed(const char *filter_desc, int *needed_frames) { const char *s = NULL; if ((s = strrchr(filter_desc, ',')) == NULL) { return 1; } if ((s = strchr(s, '\"')) == NULL) { return 1; } *needed_frames = strtol(s + 1, NULL, 0); return 0; } int optstr_param(char *buf, const char *name, const char *comment, const char *fmt, const char *val, ...) /* char *valid_from1, char *valid_to1, ... */ { va_list ap; int n = 0, res = 0, num_args=0; size_t buf_len = strlen(buf), fmt_len = strlen(fmt), pos = 0; res = tc_snprintf(buf + buf_len, ARG_CONFIG_LEN - buf_len, "\"%s\", \"%s\", \"%s\", \"%s\"", name, comment, fmt, val); if(res <= 0) { return 1; } n += res; /* count format strings */ for (pos = 0; pos < fmt_len; pos++) { if (fmt[pos] == '%') { ++num_args; /* is this one quoted with '%%' */ if (pos + 1 < fmt_len && fmt[pos + 1] == '%') { --num_args; ++pos; } } } num_args *= 2; if (num_args && optstr_is_string_arg(fmt)) { num_args = 0; } va_start(ap, val); while (num_args--) { res = tc_snprintf(buf + buf_len + n, ARG_CONFIG_LEN - buf_len - n, ", \"%s\"", va_arg(ap, char *)); if (res <= 0) { return 1; } n += res; } va_end(ap); res = tc_snprintf(buf + buf_len + n, ARG_CONFIG_LEN - buf_len - n, "\n"); if (res <= 0 ) { return 1; } return 0; } /*************************************************************************/ /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */