xref: /third_party/ffmpeg/tools/ffescape.c (revision cabdff1a)
1/*
2 * Copyright (c) 2012 Stefano Sabatini
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "config.h"
22#include <errno.h>
23#include <limits.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#if HAVE_UNISTD_H
28#include <unistd.h>             /* getopt */
29#endif
30
31#include "libavutil/log.h"
32#include "libavutil/bprint.h"
33#include "libavutil/mem.h"
34
35#if !HAVE_GETOPT
36#include "compat/getopt.c"
37#endif
38
39/**
40 * @file
41 * escaping utility
42 */
43
44static void usage(void)
45{
46    printf("Escape an input string, adopting the av_get_token() escaping logic\n");
47    printf("usage: ffescape [OPTIONS]\n");
48    printf("\n"
49           "Options:\n"
50           "-e                echo each input line on output\n"
51           "-f flag           select an escape flag, can assume the values 'whitespace' and 'strict'\n"
52           "-h                print this help\n"
53           "-i INFILE         set INFILE as input file, stdin if omitted\n"
54           "-l LEVEL          set the number of escaping levels, 1 if omitted\n"
55           "-m ESCAPE_MODE    select escape mode between 'auto', 'backslash', 'quote'\n"
56           "-o OUTFILE        set OUTFILE as output file, stdout if omitted\n"
57           "-p PROMPT         set output prompt, is '=> ' by default\n"
58           "-s SPECIAL_CHARS  set the list of special characters\n");
59}
60
61int main(int argc, char **argv)
62{
63    AVBPrint src;
64    char *src_buf, *dst_buf;
65    const char *outfilename = NULL, *infilename = NULL;
66    FILE *outfile = NULL, *infile = NULL;
67    const char *prompt = "=> ";
68    enum AVEscapeMode escape_mode = AV_ESCAPE_MODE_AUTO;
69    int escape_flags = 0;
70    int level = 1;
71    int echo = 0;
72    char *special_chars = NULL;
73    int c;
74
75    while ((c = getopt(argc, argv, "ef:hi:l:o:m:p:s:")) != -1) {
76        switch (c) {
77        case 'e':
78            echo = 1;
79            break;
80        case 'h':
81            usage();
82            return 0;
83        case 'i':
84            infilename = optarg;
85            break;
86        case 'f':
87            if      (!strcmp(optarg, "whitespace"))        escape_flags |= AV_ESCAPE_FLAG_WHITESPACE;
88            else if (!strcmp(optarg, "strict"))            escape_flags |= AV_ESCAPE_FLAG_STRICT;
89            else if (!strcmp(optarg, "xml_single_quotes")) escape_flags |= AV_ESCAPE_FLAG_XML_SINGLE_QUOTES;
90            else if (!strcmp(optarg, "xml_double_quotes")) escape_flags |= AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES;
91            else {
92                av_log(NULL, AV_LOG_ERROR,
93                       "Invalid value '%s' for option -f, "
94                       "valid arguments are 'whitespace', and 'strict'\n", optarg);
95                return 1;
96            }
97            break;
98        case 'l':
99        {
100            char *tail;
101            long int li = strtol(optarg, &tail, 10);
102            if (*tail || li > INT_MAX || li < 0) {
103                av_log(NULL, AV_LOG_ERROR,
104                        "Invalid value '%s' for option -l, argument must be a non negative integer\n",
105                        optarg);
106                return 1;
107            }
108            level = li;
109            break;
110        }
111        case 'm':
112            if      (!strcmp(optarg, "auto"))      escape_mode = AV_ESCAPE_MODE_AUTO;
113            else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH;
114            else if (!strcmp(optarg, "quote"))     escape_mode = AV_ESCAPE_MODE_QUOTE;
115            else if (!strcmp(optarg, "xml"))       escape_mode = AV_ESCAPE_MODE_XML;
116            else {
117                av_log(NULL, AV_LOG_ERROR,
118                       "Invalid value '%s' for option -m, "
119                       "valid arguments are 'backslash', and 'quote'\n", optarg);
120                return 1;
121            }
122            break;
123        case 'o':
124            outfilename = optarg;
125            break;
126        case 'p':
127            prompt = optarg;
128            break;
129        case 's':
130            special_chars = optarg;
131            break;
132        case '?':
133            return 1;
134        }
135    }
136
137    if (!infilename || !strcmp(infilename, "-")) {
138        infilename = "stdin";
139        infile = stdin;
140    } else {
141        infile = fopen(infilename, "r");
142    }
143    if (!infile) {
144        av_log(NULL, AV_LOG_ERROR, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
145        return 1;
146    }
147
148    if (!outfilename || !strcmp(outfilename, "-")) {
149        outfilename = "stdout";
150        outfile = stdout;
151    } else {
152        outfile = fopen(outfilename, "w");
153    }
154    if (!outfile) {
155        av_log(NULL, AV_LOG_ERROR, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
156        return 1;
157    }
158
159    /* grab the input and store it in src */
160    av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
161    while ((c = fgetc(infile)) != EOF)
162        av_bprint_chars(&src, c, 1);
163    av_bprint_chars(&src, 0, 1);
164
165    if (!av_bprint_is_complete(&src)) {
166        av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
167        av_bprint_finalize(&src, NULL);
168        return 1;
169    }
170    av_bprint_finalize(&src, &src_buf);
171
172    if (echo)
173        fprintf(outfile, "%s", src_buf);
174
175    /* escape */
176    dst_buf = src_buf;
177    while (level--) {
178        if (av_escape(&dst_buf, src_buf, special_chars, escape_mode, escape_flags) < 0) {
179            av_log(NULL, AV_LOG_ERROR, "Could not escape string\n");
180            return 1;
181        }
182        av_free(src_buf);
183        src_buf = dst_buf;
184    }
185
186    fprintf(outfile, "%s%s", prompt, dst_buf);
187    av_free(dst_buf);
188    return 0;
189}
190