Browse code

tools: add ffescape utility

Stefano Sabatini authored on 2012/10/15 19:17:15
Showing 4 changed files
... ...
@@ -55,6 +55,7 @@
55 55
 /tools/ffbisect
56 56
 /tools/bisect.need
57 57
 /tools/cws2fws
58
+/tools/ffescape
58 59
 /tools/ffeval
59 60
 /tools/graph2dot
60 61
 /tools/ismindex
... ...
@@ -16,6 +16,7 @@ version <next>:
16 16
 - subtitles raw text decoder
17 17
 - support for building DLLs using MSVC
18 18
 - LVF demuxer
19
+- ffescape tool
19 20
 
20 21
 
21 22
 version 1.0:
... ...
@@ -131,6 +131,6 @@ TESTPROGS = adler32                                                     \
131 131
 
132 132
 TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo
133 133
 
134
-TOOLS = ffeval
134
+TOOLS = ffeval ffescape
135 135
 
136 136
 $(SUBDIR)lzo-test$(EXESUF): ELIBS = -llzo2
137 137
new file mode 100644
... ...
@@ -0,0 +1,233 @@
0
+/*
1
+ * Copyright (c) 2012 Stefano Sabatini
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+#include "config.h"
21
+#if HAVE_UNISTD_H
22
+#include <unistd.h>             /* getopt */
23
+#endif
24
+
25
+#include "libavutil/log.h"
26
+#include "libavutil/bprint.h"
27
+
28
+#if !HAVE_GETOPT
29
+#include "compat/getopt.c"
30
+#endif
31
+
32
+/**
33
+ * @file
34
+ * escaping utility
35
+ */
36
+
37
+static void usage(void)
38
+{
39
+    printf("Escape an input string, adopting the av_get_token() escaping logic\n");
40
+    printf("usage: ffescape [OPTIONS]\n");
41
+    printf("\n"
42
+           "Options:\n"
43
+           "-e                echo each input line on output\n"
44
+           "-h                print this help\n"
45
+           "-i INFILE         set INFILE as input file, stdin if omitted\n"
46
+           "-l LEVEL          set the number of escaping levels, 1 if omitted\n"
47
+           "-m ESCAPE_MODE    select escape mode between 'full', 'lazy', 'quote', default is 'lazy'\n"
48
+           "-o OUTFILE        set OUTFILE as output file, stdout if omitted\n"
49
+           "-p PROMPT         set output prompt, is '=> ' by default\n"
50
+           "-s SPECIAL_CHARS  set the list of special characters\n");
51
+}
52
+
53
+#define WHITESPACES " \n\t"
54
+
55
+enum EscapeMode {
56
+    ESCAPE_MODE_FULL,
57
+    ESCAPE_MODE_LAZY,
58
+    ESCAPE_MODE_QUOTE,
59
+};
60
+
61
+static int escape(char **dst, const char *src, const char *special_chars,
62
+                  enum EscapeMode mode)
63
+{
64
+    AVBPrint dstbuf;
65
+
66
+    av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
67
+
68
+    switch (mode) {
69
+    case ESCAPE_MODE_FULL:
70
+    case ESCAPE_MODE_LAZY:
71
+        /* \-escape characters */
72
+
73
+        if (mode == ESCAPE_MODE_LAZY && strchr(WHITESPACES, *src))
74
+            av_bprintf(&dstbuf, "\\%c", *src++);
75
+
76
+        for (; *src; src++) {
77
+            if ((special_chars && strchr(special_chars, *src)) ||
78
+                strchr("'\\", *src) ||
79
+                (mode == ESCAPE_MODE_FULL && strchr(WHITESPACES, *src)))
80
+                av_bprintf(&dstbuf, "\\%c", *src);
81
+            else
82
+                av_bprint_chars(&dstbuf, *src, 1);
83
+        }
84
+
85
+        if (mode == ESCAPE_MODE_LAZY && strchr(WHITESPACES, dstbuf.str[dstbuf.len-1])) {
86
+            char c = dstbuf.str[dstbuf.len-1];
87
+            dstbuf.str[dstbuf.len-1] = '\\';
88
+            av_bprint_chars(&dstbuf, c, 1);
89
+        }
90
+        break;
91
+
92
+    case ESCAPE_MODE_QUOTE:
93
+        /* enclose between '' the string */
94
+        av_bprint_chars(&dstbuf, '\'', 1);
95
+        for (; *src; src++) {
96
+            if (*src == '\'')
97
+                av_bprintf(&dstbuf, "'\\''");
98
+            else
99
+                av_bprint_chars(&dstbuf, *src, 1);
100
+        }
101
+        av_bprint_chars(&dstbuf, '\'', 1);
102
+        break;
103
+
104
+    default:
105
+        /* unknown escape mode */
106
+        return AVERROR(EINVAL);
107
+    }
108
+
109
+    if (!av_bprint_is_complete(&dstbuf)) {
110
+        av_bprint_finalize(&dstbuf, NULL);
111
+        return AVERROR(ENOMEM);
112
+    } else {
113
+        av_bprint_finalize(&dstbuf, dst);
114
+        return 0;
115
+    }
116
+}
117
+
118
+int main(int argc, char **argv)
119
+{
120
+    AVBPrint src;
121
+    char *src_buf, *dst_buf;
122
+    const char *outfilename = NULL, *infilename = NULL;
123
+    FILE *outfile = NULL, *infile = NULL;
124
+    const char *prompt = "=> ";
125
+    enum EscapeMode escape_mode = ESCAPE_MODE_LAZY;
126
+    int level = 1;
127
+    int echo = 0;
128
+    char *special_chars = NULL;
129
+    int c;
130
+
131
+    while ((c = getopt(argc, argv, "ehi:l:o:m:p:s:")) != -1) {
132
+        switch (c) {
133
+        case 'e':
134
+            echo = 1;
135
+            break;
136
+        case 'h':
137
+            usage();
138
+            return 0;
139
+        case 'i':
140
+            infilename = optarg;
141
+            break;
142
+        case 'l':
143
+        {
144
+            char *tail;
145
+            long int li = strtol(optarg, &tail, 10);
146
+            if (*tail || li > INT_MAX || li < 0) {
147
+                av_log(NULL, AV_LOG_ERROR,
148
+                        "Invalid value '%s' for option -l, argument must be a non negative integer\n",
149
+                        optarg);
150
+                return 1;
151
+            }
152
+            level = li;
153
+            break;
154
+        }
155
+        case 'm':
156
+            if      (!strcmp(optarg, "full"))  escape_mode = ESCAPE_MODE_FULL;
157
+            else if (!strcmp(optarg, "lazy"))  escape_mode = ESCAPE_MODE_LAZY;
158
+            else if (!strcmp(optarg, "quote")) escape_mode = ESCAPE_MODE_QUOTE;
159
+            else {
160
+                av_log(NULL, AV_LOG_ERROR,
161
+                       "Invalid value '%s' for option -m, "
162
+                       "valid arguments are 'full', 'lazy', 'quote'\n", optarg);
163
+                return 1;
164
+            }
165
+            break;
166
+        case 'o':
167
+            outfilename = optarg;
168
+            break;
169
+        case 'p':
170
+            prompt = optarg;
171
+            break;
172
+        case 's':
173
+            special_chars = optarg;
174
+            break;
175
+        case '?':
176
+            return 1;
177
+        }
178
+    }
179
+
180
+    if (!infilename || !strcmp(infilename, "-")) {
181
+        infilename = "stdin";
182
+        infile = stdin;
183
+    } else {
184
+        infile = fopen(infilename, "r");
185
+    }
186
+    if (!infile) {
187
+        av_log(NULL, AV_LOG_ERROR, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
188
+        return 1;
189
+    }
190
+
191
+    if (!outfilename || !strcmp(outfilename, "-")) {
192
+        outfilename = "stdout";
193
+        outfile = stdout;
194
+    } else {
195
+        outfile = fopen(outfilename, "w");
196
+    }
197
+    if (!outfile) {
198
+        av_log(NULL, AV_LOG_ERROR, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
199
+        return 1;
200
+    }
201
+
202
+    /* grab the input and store it in src */
203
+    av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
204
+    while ((c = fgetc(infile)) != EOF)
205
+        av_bprint_chars(&src, c, 1);
206
+    av_bprint_chars(&src, 0, 1);
207
+
208
+    if (!av_bprint_is_complete(&src)) {
209
+        av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
210
+        av_bprint_finalize(&src, NULL);
211
+        return 1;
212
+    }
213
+    av_bprint_finalize(&src, &src_buf);
214
+
215
+    if (echo)
216
+        fprintf(outfile, "%s", src_buf);
217
+
218
+    /* escape */
219
+    dst_buf = src_buf;
220
+    while (level--) {
221
+        if (escape(&dst_buf, src_buf, special_chars, escape_mode) < 0) {
222
+            av_log(NULL, AV_LOG_ERROR, "Could not escape string\n");
223
+            return 1;
224
+        }
225
+        av_free(src_buf);
226
+        src_buf = dst_buf;
227
+    }
228
+
229
+    fprintf(outfile, "%s%s", prompt, dst_buf);
230
+    av_free(dst_buf);
231
+    return 0;
232
+}