aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Sabatini <stefasab@gmail.com>2012-12-16 12:17:23 +0100
committerStefano Sabatini <stefasab@gmail.com>2013-03-07 01:12:04 +0100
commit9767ec6b865c35f68cb6642fefeacc009f17e638 (patch)
tree6a887bbb054464e240e17d3d185ba0b2e6b63290
parent38d40ac18a3855620852e6552114caeb413497eb (diff)
downloadffmpeg-9767ec6b865c35f68cb6642fefeacc009f17e638.tar.gz
lavu: add escape API
The escape API will be useful to perform escaping programmatically, which is required when crafting argument strings, and will be used for context printing as well. This is based on the ffescape tool code, with a few extensions and fixes.
-rw-r--r--doc/APIchanges3
-rw-r--r--libavutil/avstring.c18
-rw-r--r--libavutil/avstring.h42
-rw-r--r--libavutil/bprint.c45
-rw-r--r--libavutil/bprint.h17
-rw-r--r--libavutil/version.h4
-rw-r--r--tools/ffescape.c93
7 files changed, 147 insertions, 75 deletions
diff --git a/doc/APIchanges b/doc/APIchanges
index 8535d9fe36..a1e81808e7 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,9 @@ libavutil: 2012-10-22
API changes, most recent first:
+2013-03-07 - xxxxxx - lavu 52.18.100 - avstring.h,bprint.h
+ Add av_escape() and av_bprint_escape() API.
+
2013-02-24 - xxxxxx - lavfi 3.41.100 - buffersink.h
Add sample_rates field to AVABufferSinkParams.
diff --git a/libavutil/avstring.c b/libavutil/avstring.c
index 9ad1e12711..45f8d78172 100644
--- a/libavutil/avstring.c
+++ b/libavutil/avstring.c
@@ -28,6 +28,7 @@
#include "common.h"
#include "mem.h"
#include "avstring.h"
+#include "bprint.h"
int av_strstart(const char *str, const char *pfx, const char **ptr)
{
@@ -267,6 +268,23 @@ const char *av_dirname(char *path)
return path;
}
+int av_escape(char **dst, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags)
+{
+ AVBPrint dstbuf;
+
+ av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_escape(&dstbuf, src, special_chars, mode, flags);
+
+ if (!av_bprint_is_complete(&dstbuf)) {
+ av_bprint_finalize(&dstbuf, NULL);
+ return AVERROR(ENOMEM);
+ } else {
+ av_bprint_finalize(&dstbuf, dst);
+ return dstbuf.len;
+ }
+}
+
#ifdef TEST
int main(void)
diff --git a/libavutil/avstring.h b/libavutil/avstring.h
index 3896b5f2bb..5b078f15ae 100644
--- a/libavutil/avstring.h
+++ b/libavutil/avstring.h
@@ -266,6 +266,48 @@ const char *av_basename(const char *path);
*/
const char *av_dirname(char *path);
+enum AVEscapeMode {
+ AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode.
+ AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping.
+ AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping.
+};
+
+/**
+ * Consider spaces special and escape them even in the middle of the
+ * string.
+ *
+ * This is equivalent to adding the whitespace characters to the special
+ * characters lists, except it is guaranteed to use the exact same list
+ * of whitespace characters as the rest of libavutil.
+ */
+#define AV_ESCAPE_FLAG_WHITESPACE 0x01
+
+/**
+ * Escape only specified special characters.
+ * Without this flag, escape also any characters that may be considered
+ * special by av_get_token(), such as the single quote.
+ */
+#define AV_ESCAPE_FLAG_STRICT 0x02
+
+/**
+ * Escape string in src, and put the escaped string in an allocated
+ * string in *dst, which must be freed with av_free().
+ *
+ * @param dst pointer where an allocated string is put
+ * @param src string to escape, must be non-NULL
+ * @param special_chars string containing the special characters which
+ * need to be escaped, can be NULL
+ * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
+ * Any unknown value for mode will be considered equivalent to
+ * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
+ * notice.
+ * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros
+ * @return the length of the allocated string, or a negative error code in case of error
+ * @see av_bprint_escape()
+ */
+int av_escape(char **dst, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags);
+
/**
* @}
*/
diff --git a/libavutil/bprint.c b/libavutil/bprint.c
index 4684ab4979..fd7611aaed 100644
--- a/libavutil/bprint.c
+++ b/libavutil/bprint.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <time.h>
#include "avassert.h"
+#include "avstring.h"
#include "bprint.h"
#include "common.h"
#include "error.h"
@@ -217,6 +218,50 @@ int av_bprint_finalize(AVBPrint *buf, char **ret_str)
return ret;
}
+#define WHITESPACES " \n\t"
+
+void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags)
+{
+ const char *src0 = src;
+
+ if (mode == AV_ESCAPE_MODE_AUTO)
+ mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
+
+ switch (mode) {
+ case AV_ESCAPE_MODE_QUOTE:
+ /* enclose the string between '' */
+ av_bprint_chars(dstbuf, '\'', 1);
+ for (; *src; src++) {
+ if (*src == '\'')
+ av_bprintf(dstbuf, "'\\''");
+ else
+ av_bprint_chars(dstbuf, *src, 1);
+ }
+ av_bprint_chars(dstbuf, '\'', 1);
+ break;
+
+ /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
+ default:
+ /* \-escape characters */
+ for (; *src; src++) {
+ int is_first_last = src == src0 || !*(src+1);
+ int is_ws = !!strchr(WHITESPACES, *src);
+ int is_strictly_special = special_chars && strchr(special_chars, *src);
+ int is_special =
+ is_strictly_special || strchr("'\\", *src) ||
+ (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
+
+ if (is_strictly_special ||
+ (!(flags & AV_ESCAPE_FLAG_STRICT) &&
+ (is_special || (is_ws && is_first_last))))
+ av_bprint_chars(dstbuf, '\\', 1);
+ av_bprint_chars(dstbuf, *src, 1);
+ }
+ break;
+ }
+}
+
#ifdef TEST
#undef printf
diff --git a/libavutil/bprint.h b/libavutil/bprint.h
index f3915fe7b1..df78916f4a 100644
--- a/libavutil/bprint.h
+++ b/libavutil/bprint.h
@@ -22,6 +22,7 @@
#define AVUTIL_BPRINT_H
#include "attributes.h"
+#include "avstring.h"
/**
* Define a structure with extra padding to a fixed size
@@ -180,4 +181,20 @@ static inline int av_bprint_is_complete(AVBPrint *buf)
*/
int av_bprint_finalize(AVBPrint *buf, char **ret_str);
+/**
+ * Escape the content in src and append it to dstbuf.
+ *
+ * @param dstbuf already inited destination bprint buffer
+ * @param src string containing the text to escape
+ * @param special_chars string containing the special characters which
+ * need to be escaped, can be NULL
+ * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
+ * Any unknown value for mode will be considered equivalent to
+ * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
+ * notice.
+ * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros
+ */
+void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags);
+
#endif /* AVUTIL_BPRINT_H */
diff --git a/libavutil/version.h b/libavutil/version.h
index cf65fff5f3..4cd82268db 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -75,8 +75,8 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 52
-#define LIBAVUTIL_VERSION_MINOR 17
-#define LIBAVUTIL_VERSION_MICRO 103
+#define LIBAVUTIL_VERSION_MINOR 18
+#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
diff --git a/tools/ffescape.c b/tools/ffescape.c
index d777fe4572..0530d28c6d 100644
--- a/tools/ffescape.c
+++ b/tools/ffescape.c
@@ -42,80 +42,16 @@ static void usage(void)
printf("\n"
"Options:\n"
"-e echo each input line on output\n"
+ "-f flag select an escape flag, can assume the values 'whitespace' and 'strict'\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"
- "-m ESCAPE_MODE select escape mode between 'full', 'lazy', 'quote', default is 'lazy'\n"
+ "-m ESCAPE_MODE select escape mode between 'auto', 'backslash', 'quote'\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"
-
-enum EscapeMode {
- ESCAPE_MODE_FULL,
- ESCAPE_MODE_LAZY,
- ESCAPE_MODE_QUOTE,
-};
-
-static int escape(char **dst, const char *src, const char *special_chars,
- enum EscapeMode mode)
-{
- AVBPrint dstbuf;
-
- av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
-
- switch (mode) {
- case ESCAPE_MODE_FULL:
- case ESCAPE_MODE_LAZY:
- /* \-escape characters */
-
- if (mode == ESCAPE_MODE_LAZY && strchr(WHITESPACES, *src))
- av_bprintf(&dstbuf, "\\%c", *src++);
-
- for (; *src; src++) {
- if ((special_chars && strchr(special_chars, *src)) ||
- strchr("'\\", *src) ||
- (mode == ESCAPE_MODE_FULL && strchr(WHITESPACES, *src)))
- av_bprintf(&dstbuf, "\\%c", *src);
- else
- av_bprint_chars(&dstbuf, *src, 1);
- }
-
- if (mode == ESCAPE_MODE_LAZY && strchr(WHITESPACES, dstbuf.str[dstbuf.len-1])) {
- char c = dstbuf.str[dstbuf.len-1];
- dstbuf.str[dstbuf.len-1] = '\\';
- av_bprint_chars(&dstbuf, c, 1);
- }
- break;
-
- case ESCAPE_MODE_QUOTE:
- /* enclose between '' the string */
- av_bprint_chars(&dstbuf, '\'', 1);
- for (; *src; src++) {
- if (*src == '\'')
- av_bprintf(&dstbuf, "'\\''");
- else
- av_bprint_chars(&dstbuf, *src, 1);
- }
- av_bprint_chars(&dstbuf, '\'', 1);
- break;
-
- default:
- /* unknown escape mode */
- return AVERROR(EINVAL);
- }
-
- if (!av_bprint_is_complete(&dstbuf)) {
- av_bprint_finalize(&dstbuf, NULL);
- return AVERROR(ENOMEM);
- } else {
- av_bprint_finalize(&dstbuf, dst);
- return 0;
- }
-}
-
int main(int argc, char **argv)
{
AVBPrint src;
@@ -123,13 +59,14 @@ int main(int argc, char **argv)
const char *outfilename = NULL, *infilename = NULL;
FILE *outfile = NULL, *infile = NULL;
const char *prompt = "=> ";
- enum EscapeMode escape_mode = ESCAPE_MODE_LAZY;
+ enum AVEscapeMode escape_mode = AV_ESCAPE_MODE_AUTO;
+ int escape_flags = 0;
int level = 1;
int echo = 0;
char *special_chars = NULL;
int c;
- while ((c = getopt(argc, argv, "ehi:l:o:m:p:s:")) != -1) {
+ while ((c = getopt(argc, argv, "ef:hi:l:o:m:p:s:")) != -1) {
switch (c) {
case 'e':
echo = 1;
@@ -140,6 +77,16 @@ int main(int argc, char **argv)
case 'i':
infilename = optarg;
break;
+ case 'f':
+ if (!strcmp(optarg, "whitespace")) escape_flags |= AV_ESCAPE_FLAG_WHITESPACE;
+ else if (!strcmp(optarg, "strict")) escape_flags |= AV_ESCAPE_FLAG_STRICT;
+ else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -f, "
+ "valid arguments are 'whitespace', and 'strict'\n", optarg);
+ return 1;
+ }
+ break;
case 'l':
{
char *tail;
@@ -154,13 +101,13 @@ int main(int argc, char **argv)
break;
}
case 'm':
- if (!strcmp(optarg, "full")) escape_mode = ESCAPE_MODE_FULL;
- else if (!strcmp(optarg, "lazy")) escape_mode = ESCAPE_MODE_LAZY;
- else if (!strcmp(optarg, "quote")) escape_mode = ESCAPE_MODE_QUOTE;
+ if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO;
+ else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH;
+ else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE;
else {
av_log(NULL, AV_LOG_ERROR,
"Invalid value '%s' for option -m, "
- "valid arguments are 'full', 'lazy', 'quote'\n", optarg);
+ "valid arguments are 'backslash', and 'quote'\n", optarg);
return 1;
}
break;
@@ -219,7 +166,7 @@ int main(int argc, char **argv)
/* escape */
dst_buf = src_buf;
while (level--) {
- if (escape(&dst_buf, src_buf, special_chars, escape_mode) < 0) {
+ if (av_escape(&dst_buf, src_buf, special_chars, escape_mode, escape_flags) < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not escape string\n");
return 1;
}