[geany/geany] e0a2c6: Refactoring and review comments
Thomas Martitz
git-noreply at xxxxx
Mon Dec 3 21:33:59 UTC 2018
Branch: refs/heads/master
Author: Thomas Martitz <kugel at rockbox.org>
Committer: Thomas Martitz <kugel at rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: e0a2c6277ae739de6af6c1df311fc9979b54915a
https://github.com/geany/geany/commit/e0a2c6277ae739de6af6c1df311fc9979b54915a
Log Message:
-----------
Refactoring and review comments
- Fix lots of compiler warnings
- Fix a bug where a long base name would prevent ellipsizing the longest
common substring
- rewrite utils_strv_shorten_file_list to be more clear (hopefully)
- use g_strlcpy
- optimize case where the longest common substring need not be searched for
Modified Paths:
--------------
src/utils.c
Modified: src/utils.c
115 lines changed, 63 insertions(+), 52 deletions(-)
===================================================================
@@ -2054,9 +2054,9 @@ gchar **utils_strv_join(gchar **first, gchar **second)
* @return The common prefix that is part of all strings (maybe empty), or NULL if an empty list
* was passed in.
*/
-static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
+static gchar *utils_strv_find_common_prefix(gchar **strv, gsize num)
{
- gchar *prefix, **ptr;
+ gchar *prefix;
if (!NZV(strv))
return NULL;
@@ -2068,7 +2068,7 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
for (gint i = 0; prefix[i]; i++)
{
- for (gint j = 1; j < num; j++)
+ for (gsize j = 1; j < num; j++)
{
gchar *s = strv[j];
if (s[i] != prefix[i])
@@ -2093,14 +2093,14 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
*
* @return The common prefix that is part of all strings.
*/
-gchar *utils_strv_find_lcs(gchar **strv, size_t num)
+static gchar *utils_strv_find_lcs(gchar **strv, gsize num)
{
- gchar *first, *other, *_sub, *sub;
+ gchar *first, *_sub, *sub;
gsize n_chars;
gsize len;
gsize max = 0;
char *lcs;
- gint found;
+ gsize found;
if (strv == NULL)
return NULL;
@@ -2122,11 +2122,9 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
break;
for (n_chars = 1; n_chars <= chars_left; n_chars++)
{
- /* strlcpy() ftw! */
- memcpy(sub, _sub, n_chars);
- sub[n_chars] = '\0';
+ g_strlcpy(sub, _sub, n_chars+1);
found = 1;
- for (gint i = 1; i < num; i++)
+ for (gsize i = 1; i < num; i++)
{
if (strstr(strv[i], sub) == NULL)
break;
@@ -2147,7 +2145,7 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
/** Transform file names in a list to be shorter.
*
- * This function takes a list of file names (porbably with absolute paths), and
+ * This function takes a list of file names (probably with absolute paths), and
* transforms the paths such that they are short but still unique. This is intended
* for dialogs which present the file list to the user, where the base name may result
* in duplicates (showing the full path might be inappropriate).
@@ -2163,73 +2161,86 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
* @since 1.34 (API 239)
*/
GEANY_API_SYMBOL
-gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num)
+gchar **utils_strv_shorten_file_list(gchar **file_names, gsize num)
{
- gint i, j;
- gchar *prefix, *substring, *name, *sep, **s;
- TMTag *tmtag;
+ gsize i;
+ gchar *prefix, *substring, *lcs;
+ gchar *start, *end;
gchar **names;
- gsize len;
+ gsize prefix_len, lcs_len;
/* The return value shall have exactly the same size as the input. If the input is a
* GStrv (last element is NULL), the output will follow suit. */
if (!num)
num = g_strv_length(file_names);
/* Always include a terminating NULL, enables easy freeing with g_strfreev() */
- names = g_new(gchar *, num + 1);
- names[num] = 0;
+ names = g_new0(gchar *, num + 1);
prefix = utils_strv_find_common_prefix(file_names, num);
/* First: determine the common prefix, that will be stripped.
* Don't strip single-letter prefixes, such as '/' */
- len = 0;
+ prefix_len = 0;
if (NZV(prefix) && prefix[1])
{
/* Only strip directory components, include trailing '/' */
- sep = strrchr(prefix, G_DIR_SEPARATOR);
- if (sep)
- len = sep - prefix + 1;
+ start = strrchr(prefix, G_DIR_SEPARATOR);
+ if (start)
+ prefix_len = start - prefix + 1;
}
- for (i = 0; i < num; i++)
- names[i] = g_strdup(file_names[i] + len);
+ /* Second: determine the longest common substring (lcs), that will be ellipsized. Look
+ * only at the directory parts since we don't want the file name to be detected as the lcs.
+ * Also, the first component cannot be common (since it would be part of the common prefix),
+ * so ignore that as well.
+ * Surround with dir separators so that we can easily determine the boundaries for ellipsizing. */
+ for (i = 0; i < num; i++) {
+ start = strchr(file_names[i] + prefix_len, G_DIR_SEPARATOR);
+ end = start ? strrchr(start+1, G_DIR_SEPARATOR) : NULL;
+ /* Breaking out early will also skip looking for lcs (wouldn't succeed anyway). */
+ if (!start || !end)
+ break;
+ names[i] = g_strndup(start, end-start+1);
+ }
- /* Second: determine the longest common substring, that will be ellipsized */
- substring = utils_strv_find_lcs(names, num);
+ lcs_len = 0;
+ substring = (i == num) ? utils_strv_find_lcs(names, num) : NULL;
if (NZV(substring))
{
- /* Only ellipsize directory components. Directory delimiters ought
- * to be part of the substring. If it doesn't contain at least two
- * separators, then there isn't even a single directory to ellipsize
- * (also take care to not ellipsize the base file name). */
- gchar *start;
- sep = strchr(substring, G_DIR_SEPARATOR);
-
- if (sep)
+ /* Strip leading component. */
+ start = strchr(substring, G_DIR_SEPARATOR);
+ if (start)
{
- len = 0;
- start = sep + 1;
- sep = strrchr(start, G_DIR_SEPARATOR);
- if (sep)
+ lcs = start + 1;
+ /* Strip trailing components (perhaps empty). */
+ end = strrchr(lcs, G_DIR_SEPARATOR);
+ if (end)
{
- *sep = '\0';
- len = strlen(start);
- }
- /* Don't bother for tiny substrings. */
- if (len >= 5)
- {
- for (i = 0; i < num; i++)
- {
- gchar *s = strstr(names[i], start);
- gchar *rem = s + len; /* +1 skips over the leading '/' */
- gsize copy_n = strlen(rem) + 1; /* include NUL */
- memcpy(s, "...", 3); /* Maybe replace with unicode's "…" ? */
- memmove(s+3, rem, copy_n);
- }
+ *end = '\0';
+ lcs_len = strlen(lcs);
+ /* Don't bother for tiny common parts (which are often just "." or "/"). */
+ if (lcs_len < 5)
+ lcs_len = 0;
}
}
}
+ /* Finally build the shortened list of unique file names */
+ for (i = 0; i < num; i++)
+ {
+ start = file_names[i] + prefix_len;
+ if (lcs_len == 0)
+ { /* no lcs, copy without prefix */
+ SETPTR(names[i], g_strdup(start));
+ }
+ else
+ {
+ const gchar *lcs_start = strstr(start, lcs);
+ const gchar *lcs_end = lcs_start + lcs_len;
+ /* Maybe replace with unicode's "…" ? */
+ SETPTR(names[i], g_strdup_printf("%.*s...%s", (int)(lcs_start - start), start, lcs_end));
+ }
+ }
+
g_free(substring);
g_free(prefix);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
More information about the Commits
mailing list