You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
6.3 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#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:
*/