00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #if HAVE_UNISTD_H
00023 #include <unistd.h>
00024 #endif
00025
00026 #include "libavutil/log.h"
00027 #include "libavutil/bprint.h"
00028
00029 #if !HAVE_GETOPT
00030 #include "compat/getopt.c"
00031 #endif
00032
00038 static void usage(void)
00039 {
00040 printf("Escape an input string, adopting the av_get_token() escaping logic\n");
00041 printf("usage: ffescape [OPTIONS]\n");
00042 printf("\n"
00043 "Options:\n"
00044 "-e echo each input line on output\n"
00045 "-h print this help\n"
00046 "-i INFILE set INFILE as input file, stdin if omitted\n"
00047 "-l LEVEL set the number of escaping levels, 1 if omitted\n"
00048 "-m ESCAPE_MODE select escape mode between 'full', 'lazy', 'quote', default is 'lazy'\n"
00049 "-o OUTFILE set OUTFILE as output file, stdout if omitted\n"
00050 "-p PROMPT set output prompt, is '=> ' by default\n"
00051 "-s SPECIAL_CHARS set the list of special characters\n");
00052 }
00053
00054 #define WHITESPACES " \n\t"
00055
00056 enum EscapeMode {
00057 ESCAPE_MODE_FULL,
00058 ESCAPE_MODE_LAZY,
00059 ESCAPE_MODE_QUOTE,
00060 };
00061
00062 static int escape(char **dst, const char *src, const char *special_chars,
00063 enum EscapeMode mode)
00064 {
00065 AVBPrint dstbuf;
00066
00067 av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
00068
00069 switch (mode) {
00070 case ESCAPE_MODE_FULL:
00071 case ESCAPE_MODE_LAZY:
00072
00073
00074 if (mode == ESCAPE_MODE_LAZY && strchr(WHITESPACES, *src))
00075 av_bprintf(&dstbuf, "\\%c", *src++);
00076
00077 for (; *src; src++) {
00078 if ((special_chars && strchr(special_chars, *src)) ||
00079 strchr("'\\", *src) ||
00080 (mode == ESCAPE_MODE_FULL && strchr(WHITESPACES, *src)))
00081 av_bprintf(&dstbuf, "\\%c", *src);
00082 else
00083 av_bprint_chars(&dstbuf, *src, 1);
00084 }
00085
00086 if (mode == ESCAPE_MODE_LAZY && strchr(WHITESPACES, dstbuf.str[dstbuf.len-1])) {
00087 char c = dstbuf.str[dstbuf.len-1];
00088 dstbuf.str[dstbuf.len-1] = '\\';
00089 av_bprint_chars(&dstbuf, c, 1);
00090 }
00091 break;
00092
00093 case ESCAPE_MODE_QUOTE:
00094
00095 av_bprint_chars(&dstbuf, '\'', 1);
00096 for (; *src; src++) {
00097 if (*src == '\'')
00098 av_bprintf(&dstbuf, "'\\''");
00099 else
00100 av_bprint_chars(&dstbuf, *src, 1);
00101 }
00102 av_bprint_chars(&dstbuf, '\'', 1);
00103 break;
00104
00105 default:
00106
00107 return AVERROR(EINVAL);
00108 }
00109
00110 if (!av_bprint_is_complete(&dstbuf)) {
00111 av_bprint_finalize(&dstbuf, NULL);
00112 return AVERROR(ENOMEM);
00113 } else {
00114 av_bprint_finalize(&dstbuf, dst);
00115 return 0;
00116 }
00117 }
00118
00119 int main(int argc, char **argv)
00120 {
00121 AVBPrint src;
00122 char *src_buf, *dst_buf;
00123 const char *outfilename = NULL, *infilename = NULL;
00124 FILE *outfile = NULL, *infile = NULL;
00125 const char *prompt = "=> ";
00126 enum EscapeMode escape_mode = ESCAPE_MODE_LAZY;
00127 int level = 1;
00128 int echo = 0;
00129 char *special_chars = NULL;
00130 int c;
00131
00132 while ((c = getopt(argc, argv, "ehi:l:o:m:p:s:")) != -1) {
00133 switch (c) {
00134 case 'e':
00135 echo = 1;
00136 break;
00137 case 'h':
00138 usage();
00139 return 0;
00140 case 'i':
00141 infilename = optarg;
00142 break;
00143 case 'l':
00144 {
00145 char *tail;
00146 long int li = strtol(optarg, &tail, 10);
00147 if (*tail || li > INT_MAX || li < 0) {
00148 av_log(NULL, AV_LOG_ERROR,
00149 "Invalid value '%s' for option -l, argument must be a non negative integer\n",
00150 optarg);
00151 return 1;
00152 }
00153 level = li;
00154 break;
00155 }
00156 case 'm':
00157 if (!strcmp(optarg, "full")) escape_mode = ESCAPE_MODE_FULL;
00158 else if (!strcmp(optarg, "lazy")) escape_mode = ESCAPE_MODE_LAZY;
00159 else if (!strcmp(optarg, "quote")) escape_mode = ESCAPE_MODE_QUOTE;
00160 else {
00161 av_log(NULL, AV_LOG_ERROR,
00162 "Invalid value '%s' for option -m, "
00163 "valid arguments are 'full', 'lazy', 'quote'\n", optarg);
00164 return 1;
00165 }
00166 break;
00167 case 'o':
00168 outfilename = optarg;
00169 break;
00170 case 'p':
00171 prompt = optarg;
00172 break;
00173 case 's':
00174 special_chars = optarg;
00175 break;
00176 case '?':
00177 return 1;
00178 }
00179 }
00180
00181 if (!infilename || !strcmp(infilename, "-")) {
00182 infilename = "stdin";
00183 infile = stdin;
00184 } else {
00185 infile = fopen(infilename, "r");
00186 }
00187 if (!infile) {
00188 av_log(NULL, AV_LOG_ERROR, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
00189 return 1;
00190 }
00191
00192 if (!outfilename || !strcmp(outfilename, "-")) {
00193 outfilename = "stdout";
00194 outfile = stdout;
00195 } else {
00196 outfile = fopen(outfilename, "w");
00197 }
00198 if (!outfile) {
00199 av_log(NULL, AV_LOG_ERROR, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
00200 return 1;
00201 }
00202
00203
00204 av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
00205 while ((c = fgetc(infile)) != EOF)
00206 av_bprint_chars(&src, c, 1);
00207 av_bprint_chars(&src, 0, 1);
00208
00209 if (!av_bprint_is_complete(&src)) {
00210 av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
00211 av_bprint_finalize(&src, NULL);
00212 return 1;
00213 }
00214 av_bprint_finalize(&src, &src_buf);
00215
00216 if (echo)
00217 fprintf(outfile, "%s", src_buf);
00218
00219
00220 dst_buf = src_buf;
00221 while (level--) {
00222 if (escape(&dst_buf, src_buf, special_chars, escape_mode) < 0) {
00223 av_log(NULL, AV_LOG_ERROR, "Could not escape string\n");
00224 return 1;
00225 }
00226 av_free(src_buf);
00227 src_buf = dst_buf;
00228 }
00229
00230 fprintf(outfile, "%s%s", prompt, dst_buf);
00231 av_free(dst_buf);
00232 return 0;
00233 }