From patchwork Thu Mar 30 14:33:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liu Steven X-Patchwork-Id: 3192 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.44.195 with SMTP id s186csp1586212vss; Thu, 30 Mar 2017 07:34:11 -0700 (PDT) X-Received: by 10.223.138.200 with SMTP id z8mr26674wrz.49.1490884451214; Thu, 30 Mar 2017 07:34:11 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id b74si1588937wrd.314.2017.03.30.07.34.10; Thu, 30 Mar 2017 07:34:11 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9210B689988; Thu, 30 Mar 2017 17:34:07 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from smtpbguseast2.qq.com (smtpbguseast2.qq.com [54.204.34.130]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A34846898C5 for ; Thu, 30 Mar 2017 17:34:00 +0300 (EEST) X-QQ-mid: bizesmtp8t1490884433tx8b9lgpf Received: from localhost (unknown [114.248.162.234]) by esmtp4.qq.com (ESMTP) with id ; Thu, 30 Mar 2017 22:33:52 +0800 (CST) X-QQ-SSF: 01100000000000F0FF30000A0000000 X-QQ-FEAT: 6dXuswn9i1X3Z17cDA37eAOblnlowfJA5Eg61HHbKR4Q4LtdkwqCSireWlB1Z CaIbPbuBPEKKrBP3PXdOK/nfhYrcQkJo1w6iKrps9sxDRNCRRiTwR+hccttDn1QllF86eoC V2n4qIeUgcVyeaZx/ZPqQE2ObAVj4mbKt4yj07wIbHWxBDQd+eGyX7L7Yjc/qd8Y+o3alaC 0TRce4sL/vanVzAzvV5w+nZmpcL5DQ6LHbGsjHMmgNKN4IytqysqNQRA5UCxTJ39DhJQpw3 ZHAkkKTBwWv5kv X-QQ-GoodBg: 0 From: Steven Liu To: ffmpeg-devel@ffmpeg.org Date: Thu, 30 Mar 2017 22:33:50 +0800 Message-Id: <20170330143350.4420-1-lq@chinaffmpeg.org> X-Mailer: git-send-email 2.11.0 (Apple Git-81) X-QQ-SENDSIZE: 520 X-QQ-Bgrelay: 1 Subject: [FFmpeg-devel] [PATCH] avutil/avstring: add av_strreplace API into avstring X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Steven Liu MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" refer to: http://creativeandcritical.net/str-replace-c add av_strreplace API for replace string operations. Signed-off-by: Steven Liu --- libavutil/avstring.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/avstring.h | 5 ++++ 2 files changed, 82 insertions(+) diff --git a/libavutil/avstring.c b/libavutil/avstring.c index 1787a1ef54..52e6e6cd13 100644 --- a/libavutil/avstring.c +++ b/libavutil/avstring.c @@ -231,6 +231,83 @@ int av_strncasecmp(const char *a, const char *b, size_t n) return c1 - c2; } +char *av_strreplace(const char *str, const char *from, const char *to) +{ + /* Adjust each of the below values to suit your needs. */ + /* Increment positions cache size initially by this number. */ + size_t cache_sz_inc = 16; + /* Thereafter, each time capacity needs to be increased, + * multiply the increment by this factor. */ + const size_t cache_sz_inc_factor = 3; + /* But never increment capacity by more than this number. */ + const size_t cache_sz_inc_max = 1048576; + + char *pret, *ret = NULL; + const char *pstr2, *pstr = str; + size_t i, count = 0; + uintptr_t *pos_cache_tmp, *pos_cache = NULL; + size_t cache_sz = 0; + size_t cpylen, orglen, retlen, tolen, fromlen = strlen(from); + + /* Find all matches and cache their positions. */ + while ((pstr2 = av_stristr(pstr, from))) { + count++; + /* Increase the cache size when necessary. */ + if (cache_sz < count) { + cache_sz += cache_sz_inc; + pos_cache_tmp = av_realloc(pos_cache, sizeof(*pos_cache) * cache_sz); + if (!pos_cache_tmp) { + goto end_strreplace; + } else pos_cache = pos_cache_tmp; + cache_sz_inc *= cache_sz_inc_factor; + if (cache_sz_inc > cache_sz_inc_max) { + cache_sz_inc = cache_sz_inc_max; + } + } + + pos_cache[count-1] = pstr2 - str; + pstr = pstr2 + fromlen; + } + orglen = pstr - str + strlen(pstr); + /* Allocate memory for the post-replacement string. */ + if (count > 0) { + tolen = strlen(to); + retlen = orglen + (tolen - fromlen) * count; + } else { + retlen = orglen; + } + ret = av_malloc(retlen + 1); + if (!ret) { + goto end_strreplace; + } + + if (!count) { + /* If no matches, then just duplicate the string. */ + av_strlcpy(ret, str, retlen + 1); + } else { + /* Otherwise, duplicate the string whilst performing + * the replacements using the position cache. */ + pret = ret; + memcpy(pret, str, pos_cache[0]); + pret += pos_cache[0]; + for (i = 0; i < count; i++) { + memcpy(pret, to, tolen); + pret += tolen; + pstr = str + pos_cache[i] + fromlen; + cpylen = (i == count-1 ? orglen : pos_cache[i+1]) - pos_cache[i] - fromlen; + memcpy(pret, pstr, cpylen); + pret += cpylen; + } + ret[retlen] = '\0'; + } + +end_strreplace: + /* Free the cache and return the post-replacement string, + * which will be NULL in the event of an error. */ + av_free(pos_cache); + return ret; +} + const char *av_basename(const char *path) { char *p = strrchr(path, '/'); diff --git a/libavutil/avstring.h b/libavutil/avstring.h index dd2876990f..33be8bf484 100644 --- a/libavutil/avstring.h +++ b/libavutil/avstring.h @@ -266,6 +266,11 @@ int av_strcasecmp(const char *a, const char *b); */ int av_strncasecmp(const char *a, const char *b, size_t n); +/** + * Locale-independent strings replace. + * @note This means only ASCII-range characters are replace + */ +char *av_strreplace(const char *str, const char *from, const char *to); /** * Thread safe basename.