bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] mbswidth: add new functions to handle tabs


From: Joel E. Denny
Subject: [PATCH] mbswidth: add new functions to handle tabs
Date: Mon, 11 Jan 2010 21:52:54 -0500 (EST)
User-agent: Alpine 1.00 (DEB 882 2007-12-20)

Bison currently contains a wrapper around mbsnwidth to compute screen 
columns while accounting for tabs.  Based on Bison's ChangeLog, the 
wrapper was originally written by Paul Eggert.

I'd like to use this wrapper in other projects, so I thought it would be 
nice to generalize it a little and move it to gnulib.  For example, if 
STRING starts at COLUMN and the tab-stop interval is 8, you can compute 
the column following STRING like this:

  column += mbstwidth (string, column, 8, 0);

Below is a patch, not yet pushed, to implement that and a corresponding 
mbstnwidth.  Does this duplicate any functionality already offered in 
gnulib?  Is it general enough for gnulib?

I also considered providing a means to compute line numbers at the same 
time.  However, last time I checked, counting newlines is not sufficient 
for all text file formats.  To handle it generally, we might need to scan 
for matches to some user-provided regular expression or set of literal 
strings.  For my purposes, I prefer to count lines separately and just 
pass the contents of lines I find interesting to mbstwidth.  Besides, 
counting lines doesn't really seem to fit the concept of "width".

After applying the patch below to my local gnulib and adapting Bison to 
use the new functions, Bison's test suite passes, so I feel the code is 
likely correct.  Nevertheless, at some point, I should add some formal 
tests to gnulib.

>From da35410a0fa0fab4dca3302c035f84822b3bba43 Mon Sep 17 00:00:00 2001
From: Joel E. Denny <address@hidden>
Date: Mon, 11 Jan 2010 20:31:44 -0500
Subject: [PATCH] mbswidth: add new functions to handle tabs

Generalized from code originally written by Paul Eggert for GNU
Bison.
* lib/mbswidth.c (add_column_width): New static inline function.
(mbstwidth): New function.
(mbstnwidth): New function.
* lib/mbswidth.h (mbstwidth, mbstnwidth): Prototype.
---
 ChangeLog      |   10 ++++++++++
 lib/mbswidth.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/mbswidth.h |   12 ++++++++++++
 3 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 3509cdd..d06fa7a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2010-01-11  Joel E. Denny  <address@hidden>
+
+       mbswidth: add new functions to handle tabs
+       Generalized from code originally written by Paul Eggert for GNU
+       Bison.
+       * lib/mbswidth.c (add_column_width): New static inline function.
+       (mbstwidth): New function.
+       (mbstnwidth): New function.
+       * lib/mbswidth.h (mbstwidth, mbstnwidth): Prototype.
+
 2010-01-10  Bruno Haible  <address@hidden>
 
        nproc: Work better on Linux when /proc and /sys are not mounted.
diff --git a/lib/mbswidth.c b/lib/mbswidth.c
index caf0c4d..7ead24b 100644
--- a/lib/mbswidth.c
+++ b/lib/mbswidth.c
@@ -29,6 +29,9 @@
 /* Get isprint().  */
 #include <ctype.h>
 
+/* Get INT_MAX.  */
+#include <limits.h>
+
 /* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth().  */
 #include <wchar.h>
 
@@ -165,3 +168,55 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
     }
   return width;
 }
+
+/* If BUF is null, add BUFSIZE (which in this case must be less than
+   INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
+   COLUMN.  If an overflow occurs, or might occur but is undetectable,
+   return INT_MAX.  Assume COLUMN is nonnegative.  */
+static inline int
+add_column_width (int column, char const *buf, size_t bufsize, int flags)
+{
+  size_t width;
+  unsigned int remaining_columns = INT_MAX - column;
+
+  if (buf)
+    {
+      if (INT_MAX / 2 <= bufsize)
+        return INT_MAX;
+      width = mbsnwidth (buf, bufsize, flags);
+    }
+  else
+    width = bufsize;
+  return width <= remaining_columns ? column + width : INT_MAX;
+}
+
+int
+mbstwidth (const char *string, int column, int tab, int flags)
+{
+  return mbstnwidth (string, strlen (string), column, tab, flags);
+}
+
+int
+mbstnwidth (const char *buf, size_t nbytes, int column_init, int tab,
+            int flags)
+{
+  int column = column_init;
+  char const *p0 = buf;
+  char const *p;
+  char const *lim = buf + nbytes;
+
+  for (p = buf; p < lim; p++)
+    switch (*p)
+      {
+        case '\t':
+          column = add_column_width (column, p0, p - p0, flags);
+          column = add_column_width (column, NULL,
+                                     tab - ((column - 1) % tab), flags);
+          p0 = p + 1;
+          break;
+        default:
+          break;
+      }
+  column = add_column_width (column, p0, p - p0, flags);
+  return column == INT_MAX ? INT_MAX : column - column_init;
+}
diff --git a/lib/mbswidth.h b/lib/mbswidth.h
index 0383b23..e967e49 100644
--- a/lib/mbswidth.h
+++ b/lib/mbswidth.h
@@ -54,6 +54,18 @@ extern int mbswidth (const char *string, int flags);
    starting at BUF.  */
 extern int mbsnwidth (const char *buf, size_t nbytes, int flags);
 
+/* mbstnwidth (STRING, strlen (STRING), COLUMN_INIT, TAB, FLAGS)  */
+extern int mbstwidth (const char *string, int column_init, int tab,
+                      int flags);
+
+/* Like mbsnwidth, but account for tabs with tab-stop interval TAB.
+   BUF[0] is assumed to appear at screen column COLUMN_INIT (origin 1).
+   All text in BUF is assumed to be contained on a single line.  The
+   next screen column after the text in BUF is COLUMN_INIT plus the
+   width returned.  However, INT_MAX is returned instead if the new
+   screen column cannot be computed without risking an overflow.  */
+extern int mbstnwidth (const char *buf, size_t nbytes, int column_init,
+                       int tab, int flags);
 
 #ifdef __cplusplus
 }
-- 
1.5.4.3





reply via email to

[Prev in Thread] Current Thread [Next in Thread]