[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