gbranden pushed a commit to branch master
in repository groff.

commit d667fb0b0f10e0504b3f8fab33fa088c9e4ef3d5
Author: G. Branden Robinson <[email protected]>
AuthorDate: Sat Jun 6 09:31:43 2026 -0500

    Refactor groff's bespoke `string` class.
    
    ...to use `size_t` instead of `int` to track array sizes and indices.
    
    * src/include/stringclass.h: Update declarations and `inline` function
      definitions.
    * src/libs/libgroff/string.cpp: Update definitions and local variables.
      Drop now tautologically true assert(3)ions.
    
      (string::remove_spaces): This function searches for spaces backward
      from the end of the string contents.  Alter loop invariant from a
      non-negative array index (now impossible) to one that is less than the
      array length.  Discard now-unreachable logic branch.
    
    * src/preproc/eqn/lex.cpp (add_quoted_context):
    * src/preproc/preconv/preconv.cpp (get_tag_lines):
    * src/preproc/refer/label.ypp (format_serial)
      (alternative_expr::evaluate)
      (substitute_expr::evaluate)
      (int_set::set)
      (int_set::get):
    * src/preproc/refer/ref.cpp (reference::canonicalize_authors):
    * src/preproc/tbl/table.cpp (table::add_entry): Retype variables
      populated by or compared to applicable `string` member functions from
      `int` to `size_t`.
---
 ChangeLog                         | 27 +++++++++++++
 src/devices/grohtml/post-html.cpp |  2 +-
 src/include/stringclass.h         | 43 +++++++++++----------
 src/libs/libgroff/string.cpp      | 80 +++++++++++++++++----------------------
 src/preproc/eqn/lex.cpp           |  2 +-
 src/preproc/preconv/preconv.cpp   |  2 +-
 src/preproc/refer/label.ypp       | 12 +++---
 src/preproc/refer/ref.cpp         |  2 +-
 src/preproc/tbl/table.cpp         |  2 +-
 9 files changed, 94 insertions(+), 78 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c1494ed7b..f8d30c8e0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2026-06-06  G. Branden Robinson <[email protected]>
+
+       Refactor groff's bespoke `string` class to use `size_t` instead
+       of `int` to track array sizes and indices.
+
+       * src/include/stringclass.h: Update declarations and `inline`
+       function definitions.
+       * src/libs/libgroff/string.cpp: Update definitions and local
+       variables.  Drop now tautologically true assert(3)ions.
+       (string::remove_spaces): This function searches for spaces
+       backward from the end of the string contents.  Alter loop
+       invariant from a non-negative array index (now impossible) to
+       one that is less than the array length.  Discard now-unreachable
+       logic branch.
+
+       * src/preproc/eqn/lex.cpp (add_quoted_context):
+       * src/preproc/preconv/preconv.cpp (get_tag_lines):
+       * src/preproc/refer/label.ypp (format_serial)
+       (alternative_expr::evaluate)
+       (substitute_expr::evaluate)
+       (int_set::set)
+       (int_set::get):
+       * src/preproc/refer/ref.cpp (reference::canonicalize_authors):
+       * src/preproc/tbl/table.cpp (table::add_entry): Retype variables
+       populated by or compared to applicable `string` member functions
+       from `int` to `size_t`.
+
 2026-06-06  G. Branden Robinson <[email protected]>
 
        * src/libs/libgroff/string.cpp: Drop unnecessary prototypes of
diff --git a/src/devices/grohtml/post-html.cpp 
b/src/devices/grohtml/post-html.cpp
index a5e5e8bc8..2cc72c314 100644
--- a/src/devices/grohtml/post-html.cpp
+++ b/src/devices/grohtml/post-html.cpp
@@ -2862,7 +2862,7 @@ void html_printer::write_header (void)
 void html_printer::determine_header_level (int level)
 {
   if (0 == level) {
-    int i;
+    size_t i;
 
     for (i = 0; ((i<header.header_buffer.length())
                 && (('.' == header.header_buffer[i])
diff --git a/src/include/stringclass.h b/src/include/stringclass.h
index 93ecc2934..0df2363dd 100644
--- a/src/include/stringclass.h
+++ b/src/include/stringclass.h
@@ -42,7 +42,7 @@ public:
   string();
   string(const string &);
   string(const char *);
-  string(const char *, int);
+  string(const char *, size_t);
   string(char);
 
   ~string();
@@ -54,22 +54,22 @@ public:
   string &operator+=(const string &);
   string &operator+=(const char *);
   string &operator+=(char);
-  void append(const char *, int);
+  void append(const char *, size_t);
 
-  int length() const;
+  size_t length() const;
   bool empty() const;
-  int operator*() const;
+  size_t operator*() const;
 
-  string substring(int i, int n) const;
+  string substring(size_t i, size_t n) const;
 
-  char &operator[](int);
-  char operator[](int) const;
+  char &operator[](size_t);
+  char operator[](size_t) const;
 
-  void set_length(int i);
+  void set_length(size_t i);
   const char *contents() const;
   int search(const char) const;
   bool contains(const char) const;
-  int find(const char *) const;
+  size_t find(const char *) const;
   char *extract() const;
   size_t json_length() const;
   const char *json_extract() const;
@@ -93,27 +93,28 @@ public:
 
 private:
   char *ptr;
-  int len;
-  int sz;
+  size_t len;
+  size_t sz;
 
-  string(const char *, int, const char *, int);        // for use by operator+
+  // for use by operator+
+  string(const char *, size_t, const char *, size_t);
   void grow1();
 };
 
 
-inline char &string::operator[](int i)
+inline char &string::operator[](size_t i)
 {
-  assert((i >= 0) && (i < len));
+  assert(i < len);
   return ptr[i];
 }
 
-inline char string::operator[](int i) const
+inline char string::operator[](size_t i) const
 {
-  assert((i >= 0) && (i < len));
+  assert(i < len);
   return ptr[i];
 }
 
-inline int string::length() const
+inline size_t string::length() const
 {
   return len;
 }
@@ -123,7 +124,7 @@ inline bool string::empty() const
   return (len == 0);
 }
 
-inline int string::operator*() const
+inline size_t string::operator*() const
 {
   return len;
 }
@@ -172,9 +173,9 @@ inline bool operator!=(const string &s1, const string &s2)
          || (s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) != 0));
 }
 
-inline string string::substring(int i, int n) const
+inline string string::substring(size_t i, size_t n) const
 {
-  assert((i >= 0) && ((i + n) <= len));
+  assert((i + n) <= len);
   return string(ptr + i, n);
 }
 
@@ -188,7 +189,7 @@ inline string &string::operator+=(char c)
 
 void put_string(const string &, FILE *);
 
-string as_string(int);
+string as_string(size_t);
 
 #endif // GROFF_STRINGCLASS_H
 
diff --git a/src/libs/libgroff/string.cpp b/src/libs/libgroff/string.cpp
index 06e2586c5..cd821fbf5 100644
--- a/src/libs/libgroff/string.cpp
+++ b/src/libs/libgroff/string.cpp
@@ -39,7 +39,7 @@ along with this program.  If not, see 
<http://www.gnu.org/licenses/>. */
 // TODO 1: Replace all this memory management stuff with vector<char>.
 // TODO 2: Replace this entire class.  See Savannah #67735.
 
-static char *salloc(int len, int *sizep)
+static char *salloc(size_t len, size_t *sizep)
 {
   if (0 == len) {
     *sizep = 0;
@@ -59,12 +59,13 @@ static char *salloc(int len, int *sizep)
   return p;
 }
 
-static void sfree(char *ptr, int)
+static void sfree(char *ptr, size_t)
 {
   delete[] ptr;
 }
 
-static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep)
+static char *sfree_alloc(char *ptr, size_t oldsz, size_t len,
+                        size_t *sizep)
 {
   if (oldsz >= len) {
     *sizep = oldsz;
@@ -89,8 +90,8 @@ static char *sfree_alloc(char *ptr, int oldsz, int len, int 
*sizep)
   return p;
 }
 
-static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen,
-                     int *sizep)
+static char *srealloc(char *ptr, size_t oldsz, size_t oldlen,
+                     size_t newlen, size_t *sizep)
 {
   if (oldsz >= newlen) {
     *sizep = oldsz;
@@ -124,9 +125,8 @@ string::string() : ptr(0 /* nullptr */), len(0), sz(0)
 {
 }
 
-string::string(const char *p, int n) : len(n)
+string::string(const char *p, size_t n) : len(n)
 {
-  assert(n >= 0);
   ptr = salloc(n, &sz);
   if (sz > 0)
     memset(ptr, 0, sz);
@@ -225,7 +225,7 @@ string &string::operator+=(const char *p)
 {
   if (p != 0 /* nullptr */) {
     size_t n = strlen(p);
-    int newlen = len + n;
+    size_t newlen = len + n;
     if (newlen > sz)
       ptr = srealloc(ptr, sz, len, newlen, &sz);
     memcpy(ptr + len, p, n);
@@ -237,7 +237,7 @@ string &string::operator+=(const char *p)
 string &string::operator+=(const string &s)
 {
   if (s.len != 0) {
-    int newlen = len + s.len;
+    size_t newlen = len + s.len;
     if (newlen > sz)
       ptr = srealloc(ptr, sz, len, newlen, &sz);
     memcpy(ptr + len, s.ptr, s.len);
@@ -246,10 +246,10 @@ string &string::operator+=(const string &s)
   return *this;
 }
 
-void string::append(const char *p, int n)
+void string::append(const char *p, size_t n)
 {
   if (n > 0) {
-    int newlen = len + n;
+    size_t newlen = len + n;
     if (newlen > sz)
       ptr = srealloc(ptr, sz, len, newlen, &sz);
     memcpy(ptr + len, p, n);
@@ -257,9 +257,8 @@ void string::append(const char *p, int n)
   }
 }
 
-string::string(const char *s1, int n1, const char *s2, int n2)
+string::string(const char *s1, size_t n1, const char *s2, size_t n2)
 {
-  assert((n1 >= 0) && (n2 >= 0));
   len = n1 + n2;
   if (0 == len) {
     sz = 0;
@@ -305,9 +304,8 @@ bool operator>(const string &s1, const string &s2)
          : ((s1.len != 0) && (memcmp(s1.ptr, s2.ptr, s1.len) > 0)));
 }
 
-void string::set_length(int i)
+void string::set_length(size_t i)
 {
-  assert(i >= 0);
   if (i > sz)
     ptr = srealloc(ptr, sz, len, i, &sz);
   len = i;
@@ -334,7 +332,7 @@ bool string::contains(const char c) const
 }
 
 // Return index of substring `c` in string, -1 if not found.
-int string::find(const char *c) const
+size_t string::find(const char *c) const
 {
   const char *p = ptr
                  ? static_cast<const char *>(memmem(ptr, len, c,
@@ -349,9 +347,9 @@ int string::find(const char *c) const
 char *string::extract() const
 {
   char *p = ptr;
-  int n = len;
+  size_t n = len;
   int nnuls = 0;
-  int i;
+  size_t i;
   for (i = 0; i < n; i++)
     if (p[i] == '\0')
       nnuls++;
@@ -438,8 +436,8 @@ void string::json_dump() const
 
 void string::remove_spaces()
 {
-  int l = len - 1;
-  while ((l >= 0) && (ptr[l] == ' '))
+  size_t l = len - 1;
+  while ((l < len) && (ptr[l] == ' '))
     l--;
   char *p = ptr;
   if (l > 0)
@@ -448,45 +446,35 @@ void string::remove_spaces()
       l--;
     }
   if (len - 1 != l) {
-    if (l >= 0) {
-      len = l + 1;
-      char *tmp = 0 /* nullptr */;
-      assert(sz > 0);
-      try {
-       tmp = new char[sz];
-      }
-      catch (const std::bad_alloc &exc) {
-       fatal("cannot allocate %1 bytes for removal of spaces",
-             " from string", sz);
-      }
-      memset(tmp, 0, sz);
-      memcpy(tmp, p, len);
-      delete[] ptr;
-      ptr = tmp;
+    len = l + 1;
+    char *tmp = 0 /* nullptr */;
+    assert(sz > 0);
+    try {
+      tmp = new char[sz];
     }
-    else {
-      len = 0;
-      if (ptr) {
-       delete[] ptr;
-       ptr = 0 /* nullptr */;
-       sz = 0;
-      }
+    catch (const std::bad_alloc &exc) {
+      fatal("cannot allocate %1 bytes for removal of spaces",
+           " from string", sz);
     }
+    memset(tmp, 0, sz);
+    memcpy(tmp, p, len);
+    delete[] ptr;
+    ptr = tmp;
   }
 }
 
 void put_string(const string &s, FILE *fp)
 {
-  int len = s.length();
+  size_t len = s.length();
   const char *ptr = s.contents();
-  for (int i = 0; i < len; i++)
+  for (size_t i = 0; i < len; i++)
     putc(ptr[i], fp);
 }
 
-string as_string(int i)
+string as_string(size_t i)
 {
   static char buf[INT_DIGITS + 2];
-  sprintf(buf, "%d", i);
+  sprintf(buf, "%lu", i);
   return string(buf);
 }
 
diff --git a/src/preproc/eqn/lex.cpp b/src/preproc/eqn/lex.cpp
index 4e2370a1d..4f53b904e 100644
--- a/src/preproc/eqn/lex.cpp
+++ b/src/preproc/eqn/lex.cpp
@@ -689,7 +689,7 @@ static void add_quoted_context(const string &s)
 {
   string &r = context_ring[context_index];
   r = '"';
-  for (int i = 0; i < s.length(); i++)
+  for (size_t i = 0; i < s.length(); i++)
     if (s[i] == '"')
       r += "\\\"";
     else
diff --git a/src/preproc/preconv/preconv.cpp b/src/preproc/preconv/preconv.cpp
index 05263125a..cd13b5070 100644
--- a/src/preproc/preconv/preconv.cpp
+++ b/src/preproc/preconv/preconv.cpp
@@ -854,7 +854,7 @@ get_tag_lines(FILE *fp, string &data)
   int newline_count = 0;
   int c, prev = -1;
   // Handle CR, LF, and CRLF as line separators.
-  for (int i = 0; i < data.length(); i++) {
+  for (size_t i = 0; i < data.length(); i++) {
     c = data[i];
     if (c == '\n' || c == '\r')
       newline_count++;
diff --git a/src/preproc/refer/label.ypp b/src/preproc/refer/label.ypp
index 7c8774340..a29eb84bd 100644
--- a/src/preproc/refer/label.ypp
+++ b/src/preproc/refer/label.ypp
@@ -34,7 +34,7 @@ static const char *format_serial(char c, int n);
 
 struct label_info {
   int start;
-  int length;
+  size_t length;
   int count;
   int total;
   label_info(const string &);
@@ -785,7 +785,7 @@ void truncate_expr::evaluate(int tentative, const reference 
&ref,
 void alternative_expr::evaluate(int tentative, const reference &ref,
                                string &result, substring_position &pos)
 {
-  int start_length = result.length();
+  size_t start_length = result.length();
   if (expr1)
     expr1->evaluate(tentative, ref, result, pos);
   if (result.length() == start_length && expr2)
@@ -804,7 +804,7 @@ void list_expr::evaluate(int tentative, const reference 
&ref,
 void substitute_expr::evaluate(int tentative, const reference &ref,
                               string &result, substring_position &pos)
 {
-  int start_length = result.length();
+  size_t start_length = result.length();
   if (expr1)
     expr1->evaluate(tentative, ref, result, pos);
   if (result.length() > start_length && result[result.length() - 1] == '-') {
@@ -1111,11 +1111,11 @@ int same_author_name(const reference &r1, const 
reference &r2, int n)
 void int_set::set(int i)
 {
   assert(i >= 0);
-  int bytei = i >> 3;
+  size_t bytei = i >> 3;
   if (bytei >= v.length()) {
     int old_length = v.length();
     v.set_length(bytei + 1);
-    for (int j = old_length; j <= bytei; j++)
+    for (size_t j = old_length; j <= bytei; j++)
       v[j] = 0;
   }
   v[bytei] |= 1 << (i & 7);
@@ -1124,7 +1124,7 @@ void int_set::set(int i)
 int int_set::get(int i) const
 {
   assert(i >= 0);
-  int bytei = i >> 3;
+  size_t bytei = i >> 3;
   return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0;
 }
 
diff --git a/src/preproc/refer/ref.cpp b/src/preproc/refer/ref.cpp
index 778af6f22..95917c8ef 100644
--- a/src/preproc/refer/ref.cpp
+++ b/src/preproc/refer/ref.cpp
@@ -471,7 +471,7 @@ void reference::sortify_authors(int n, string &result) const
 
 void reference::canonicalize_authors(string &result) const
 {
-  int len = result.length();
+  size_t len = result.length();
   sortify_authors(INT_MAX, result);
   if (result.length() > len)
     result += SORT_SUB_SEP;
diff --git a/src/preproc/tbl/table.cpp b/src/preproc/tbl/table.cpp
index fdceaa5b4..7fbbb26d5 100644
--- a/src/preproc/tbl/table.cpp
+++ b/src/preproc/tbl/table.cpp
@@ -1538,7 +1538,7 @@ void table::add_entry(int r, int c, const string &str,
 {
   allocate(r);
   table_entry *e = 0 /* nullptr */;
-  int len = str.length();
+  size_t len = str.length();
   char *s = str.extract();
   // Diagnose escape sequences that can wreak havoc in generated output.
   if (len > 1) {

_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit

Reply via email to