[FFmpeg-devel] [PATCH] tools: add ffescape utility

Nicolas George nicolas.george at normalesup.org
Mon Oct 22 17:47:26 CEST 2012


Le primidi 1er brumaire, an CCXXI, Stefano Sabatini a écrit :
> >From 9c8a31416465147edf2c433084eae4a649a1dac3 Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Mon, 15 Oct 2012 12:17:15 +0200
> Subject: [PATCH] tools: add ffescape utility
> 
> ---
>  .gitignore         |    1 +
>  libavutil/Makefile |    2 +-
>  tools/ffescape.c   |  181 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 183 insertions(+), 1 deletions(-)
>  create mode 100644 tools/ffescape.c
> 
> diff --git a/.gitignore b/.gitignore
> index 0b00f07..2c8cd17 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -56,6 +56,7 @@
>  /tools/bisect.need
>  /tools/cws2fws
>  /tools/ffeval
> +/tools/ffescape
>  /tools/graph2dot
>  /tools/ismindex
>  /tools/pktdumper
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 63a48be..e0dd816 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -130,6 +130,6 @@ TESTPROGS = adler32                                                     \
>  
>  TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo
>  
> -TOOLS = ffeval
> +TOOLS = ffeval ffescape
>  
>  $(SUBDIR)lzo-test$(EXESUF): ELIBS = -llzo2
> diff --git a/tools/ffescape.c b/tools/ffescape.c
> new file mode 100644
> index 0000000..cb189a9
> --- /dev/null
> +++ b/tools/ffescape.c
> @@ -0,0 +1,181 @@
> +/*
> + * Copyright (c) 2012 Stefano Sabatini
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "config.h"
> +#if HAVE_UNISTD_H
> +#include <unistd.h>             /* getopt */
> +#endif
> +
> +#include "libavutil/log.h"
> +#include "libavutil/bprint.h"
> +
> +#if !HAVE_GETOPT
> +#include "compat/getopt.c"
> +#endif
> +
> +/**
> + * @file
> + * escaping utility
> + */
> +
> +static void usage(void)
> +{
> +    printf("Escape an input string, adopting the av_get_token() escaping logic\n");
> +    printf("usage: ffescape [OPTIONS]\n");
> +    printf("\n"
> +           "Options:\n"
> +           "-e                echo each input line on output\n"
> +           "-h                print this help\n"
> +           "-i INFILE         set INFILE as input file, stdin if omitted\n"
> +           "-l LEVEL          set the number of escaping levels, 1 if omitted\n"
> +           "-o OUTFILE        set OUTFILE as output file, stdout if omitted\n"
> +           "-p PROMPT         set output prompt, is '=> ' by default\n"
> +           "-s SPECIAL_CHARS  set the list of special characters\n");
> +}
> +
> +#define WHITESPACES " \n\t"

We really need to unify that.

> +
> +static char *escape(const char *src, const char *special_chars)

I believe you could make the program simpler if this function would take the
bprint buffer as argument: it would just have to add to it, and all errors
checks and finalization would go outside. Without that, it looks like you
need to check for out-of-memory twice: once before returning from escape,
and a second time after the call to escape.

> +{
> +    AVBPrint dst;
> +    char *ret;
> +
> +    av_bprint_init(&dst, 1, AV_BPRINT_SIZE_UNLIMITED);
> +    for (; *src; src++) {
> +        if ((special_chars && strchr(special_chars, *src)) ||
> +            strchr("'\\" WHITESPACES, *src))
> +            av_bprintf(&dst, "\\%c", *src);
> +        else
> +            av_bprint_chars(&dst, *src, 1);

I believe the escaping could be made more elegant: count the number of
special chars S and the number of single quotes Q, if S > kQ, escape using
single quotes (the single quotes themselves being escaped as '\'', therefore
k=3 is a good guess), else escape using backslashes.

> +    }
> +
> +    if (!av_bprint_is_complete(&dst)) {
> +        av_bprint_finalize(&dst, NULL);
> +        return NULL;
> +    } else {
> +        av_bprint_finalize(&dst, &ret);
> +        return ret;
> +    }
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    AVBPrint src;
> +    char *src_buf, *dst_buf;
> +    const char *outfilename = NULL, *infilename = NULL;
> +    FILE *outfile = NULL, *infile = NULL;
> +    const char *prompt = "=> ";
> +    int level = 1;
> +    int echo = 0;
> +    char *special_chars = NULL;
> +    int c;
> +
> +    while ((c = getopt(argc, argv, "ehi:l:o:p:s:")) != -1) {
> +        switch (c) {
> +        case 'e':
> +            echo = 1;
> +            break;
> +        case 'h':
> +            usage();
> +            return 0;
> +        case 'i':
> +            infilename = optarg;
> +            break;

Do we really need to duplicate the shell's features?

> +        case 'l':
> +        {
> +            char *tail;
> +            long int li = strtol(optarg, &tail, 10);
> +            if (*tail || li > INT_MAX || li < 0) {
> +                av_log(NULL, AV_LOG_ERROR,
> +                        "Invalid value '%s' for option -l, argument must be a non negative integer\n",
> +                        optarg);
> +                return 1;
> +            }
> +            level = li;
> +            break;
> +        }
> +        case 'o':
> +            outfilename = optarg;
> +            break;
> +        case 'p':
> +            prompt = optarg;
> +            break;
> +        case 's':
> +            special_chars = optarg;
> +            break;

> +        case '?':
> +            return 1;

usage?

> +        }
> +    }
> +
> +    if (!infilename || !strcmp(infilename, "-")) {
> +        infilename = "stdin";
> +        infile = stdin;
> +    } else {
> +        infile = fopen(infilename, "r");
> +    }
> +    if (!infile) {
> +        av_log(NULL, AV_LOG_ERROR, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
> +        return 1;
> +    }
> +
> +    if (!outfilename || !strcmp(outfilename, "-")) {
> +        outfilename = "stdout";
> +        outfile = stdout;
> +    } else {
> +        outfile = fopen(outfilename, "w");
> +    }
> +    if (!outfile) {
> +        av_log(NULL, AV_LOG_ERROR, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
> +        return 1;
> +    }
> +
> +    /* grab the input and store it in src */
> +    av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
> +    while ((c = fgetc(infile)) != EOF)
> +        av_bprint_chars(&src, c, 1);
> +    av_bprint_chars(&src, 0, 1);
> +
> +    if (!av_bprint_is_complete(&src)) {
> +        av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
> +        av_bprint_finalize(&src, NULL);
> +        return 1;
> +    }
> +    av_bprint_finalize(&src, &src_buf);
> +
> +    if (echo)
> +        fprintf(outfile, "%s ", src_buf);
> +
> +    /* escape */
> +    dst_buf = src_buf;
> +    while (level--) {
> +        dst_buf = escape(src_buf, special_chars);
> +        if (!dst_buf) {
> +            av_log(NULL, AV_LOG_ERROR, "Could not allocate buffer for the escaped string\n");
> +            return 1;
> +        }
> +        av_free(src_buf);
> +        src_buf = dst_buf;
> +    }
> +
> +    fprintf(outfile, "%s%s", prompt, dst_buf);
> +    av_free(dst_buf);
> +    return 0;
> +}

Regards,

-- 
  Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20121022/bf0f0918/attachment.asc>


More information about the ffmpeg-devel mailing list