One mildly interesting thing I noticed while writing this patch is
that gcc will give the following warning, but clang will not:

    table.rows[table.nrows++] = xinmalloc (table.ncolumns,
                                           sizeof *table.rows[0]);

    src/df.c: In function 'alloc_table_row':
    src/df.c:381:25: warning: operation on 'table.nrows' may be undefined 
[-Wsequence-point]
      381 |   table.rows[table.nrows++] = xinmalloc (table.ncolumns,
          |              ~~~~~~~~~~~^~

It only shows up when COUNTED_BY is in use. Whether it is correct to
warn is unclear to me. My memory of that area of the standard is poor.

-- 8< --

* src/df.c (table): Define as a struct containing the previously global
variables. Use COUNTED_BY.
(columns, ncolumns, ncolumns_alloc, nrows, nrows_alloc): Move into the
table struct.
(alloc_table_row, print_table, alloc_field, get_field_list, get_header)
(get_dev): Update uses of the previously existing globals to reference
the table struct.
---
 src/df.c | 87 ++++++++++++++++++++++++++++++++------------------------
 1 file changed, 50 insertions(+), 37 deletions(-)

diff --git a/src/df.c b/src/df.c
index b3d83f505..969d09aab 100644
--- a/src/df.c
+++ b/src/df.c
@@ -216,11 +216,26 @@ static char const *all_args_string =
   "source,fstype,itotal,iused,iavail,ipcent,size,"
   "used,avail,pcent,file,target";
 
-/* Storage for the definition of output columns.  */
-static struct field_data_t **columns;
+static struct
+{
+  /* The current number of processed rows (including header).  */
+  idx_t nrows;
+
+  /* The number of slots allocated for rows.  */
+  idx_t nrows_alloc;
+
+  /* Storage for pointers for each string (cell of table).  */
+  char ***rows COUNTED_BY (nrows);
+
+  /* The current number of output columns.  */
+  idx_t ncolumns;
 
-/* The current and allocated number of output columns.  */
-static idx_t ncolumns, ncolumns_alloc;
+  /* The allocated number of output columns.  */
+  idx_t ncolumns_alloc;
+
+  /* Storage for the definition of output columns.  */
+  struct field_data_t **columns COUNTED_BY (ncolumns);
+} table;
 
 /* Field values.  */
 struct field_values_t
@@ -235,13 +250,6 @@ struct field_values_t
   bool negate_used;
 };
 
-/* Storage for pointers for each string (cell of table).  */
-static char ***table;
-
-/* The current number of processed rows (including header),
-   and the number of slots allocated for rows.  */
-static idx_t nrows, nrows_alloc;
-
 /* For long options that have no equivalent short option, use a
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
@@ -361,15 +369,17 @@ replace_problematic_chars (char *cell)
 }
 
 
-/* Dynamically allocate a row of pointers in TABLE, which
+/* Dynamically allocate a row of pointers in TABLE.ROWS, which
    can then be accessed with standard 2D array notation.  */
 
 static void
 alloc_table_row (void)
 {
-  if (nrows == nrows_alloc)
-    table = xpalloc (table, &nrows_alloc, 1, -1, sizeof *table);
-  table[nrows++] = xinmalloc (ncolumns, sizeof *table[0]);
+  if (table.nrows == table.nrows_alloc)
+    table.rows = xpalloc (table.rows, &table.nrows_alloc, 1, -1,
+                          sizeof *table.rows);
+  idx_t const row_idx = table.nrows++;
+  table.rows[row_idx] = xinmalloc (table.ncolumns, sizeof *table.rows[0]);
 }
 
 /* Output each cell in the table, accounting for the
@@ -378,11 +388,11 @@ alloc_table_row (void)
 static void
 print_table (void)
 {
-  for (idx_t row = 0; row < nrows; row++)
+  for (idx_t row = 0; row < table.nrows; row++)
     {
-      for (idx_t col = 0; col < ncolumns; col++)
+      for (idx_t col = 0; col < table.ncolumns; col++)
         {
-          char *cell = table[row][col];
+          char *cell = table.rows[row][col];
 
           /* Note the SOURCE_FIELD used to be displayed on it's own line
              if (!posix_format && mbswidth (cell) > 20), but that
@@ -392,12 +402,12 @@ print_table (void)
             putchar (' ');
 
           int width = mbswidth (cell, MBSWIDTH_FLAGS);
-          int fill = width < 0 ? 0 : columns[col]->width - width;
-          if (columns[col]->align_right)
+          int fill = width < 0 ? 0 : table.columns[col]->width - width;
+          if (table.columns[col]->align_right)
             for (; 0 < fill; fill--)
               putchar (' ');
           fputs (cell, stdout);
-          if (col + 1 < ncolumns)
+          if (col + 1 < table.ncolumns)
             for (; 0 < fill; fill--)
               putchar (' ');
         }
@@ -405,15 +415,17 @@ print_table (void)
     }
 }
 
-/* Dynamically allocate a struct field_t in COLUMNS, which
+/* Dynamically allocate a struct field_t in TABLE.COLUMNS, which
    can then be accessed with standard array notation.  */
 
 static void
 alloc_field (int f, char const *c)
 {
-  if (ncolumns == ncolumns_alloc)
-    columns = xpalloc (columns, &ncolumns_alloc, 1, -1, sizeof *columns);
-  columns[ncolumns++] = &field_data[f];
+  if (table.ncolumns == table.ncolumns_alloc)
+    table.columns = xpalloc (table.columns, &table.ncolumns_alloc, 1, -1,
+                             sizeof *table.columns);
+  idx_t const column_idx = table.ncolumns++;
+  table.columns[column_idx] = &field_data[f];
   if (c != NULL)
     field_data[f].caption = c;
 
@@ -550,7 +562,7 @@ get_field_list (void)
       break;
 
     case OUTPUT_MODE:
-      if (!ncolumns)
+      if (!table.ncolumns)
         {
           /* Add all fields if --output was given without a field list.  */
           decode_output_arg (all_args_string);
@@ -569,12 +581,12 @@ get_header (void)
 {
   alloc_table_row ();
 
-  for (idx_t col = 0; col < ncolumns; col++)
+  for (idx_t col = 0; col < table.ncolumns; col++)
     {
       char *cell;
-      char const *header = _(columns[col]->caption);
+      char const *header = _(table.columns[col]->caption);
 
-      if (columns[col]->field == SIZE_FIELD
+      if (table.columns[col]->field == SIZE_FIELD
           && (header_mode == DEFAULT_MODE
               || (header_mode == OUTPUT_MODE
                   && !(human_output_opts & human_autoscale))))
@@ -616,7 +628,8 @@ get_header (void)
           /* TRANSLATORS: this is the "1K-blocks" header in "df" output.  */
           cell = xasprintf (_("%s-%s"), num, header);
         }
-      else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
+      else if (header_mode == POSIX_MODE
+               && table.columns[col]->field == SIZE_FIELD)
         {
           /* TRANSLATORS: this is the "1024-blocks" header in "df -P".  */
           cell = xasprintf (_("%ju-%s"), output_block_size, header);
@@ -626,10 +639,10 @@ get_header (void)
 
       replace_problematic_chars (cell);
 
-      table[nrows - 1][col] = cell;
+      table.rows[table.nrows - 1][col] = cell;
 
       int cell_width = mbswidth (cell, MBSWIDTH_FLAGS);
-      columns[col]->width = MAX (columns[col]->width, cell_width);
+      table.columns[col]->width = MAX (table.columns[col]->width, cell_width);
     }
 }
 
@@ -1109,13 +1122,13 @@ get_dev (char const *device, char const *mount_point, 
char const *file,
   if (print_grand_total && ! force_fsu)
     add_to_grand_total (&block_values, &inode_values);
 
-  for (idx_t col = 0; col < ncolumns; col++)
+  for (idx_t col = 0; col < table.ncolumns; col++)
     {
       char buf[LONGEST_HUMAN_READABLE + 2];
       char *cell;
 
       struct field_values_t *v;
-      switch (columns[col]->field_type)
+      switch (table.columns[col]->field_type)
         {
         case BLOCK_FLD:
           v = &block_values;
@@ -1130,7 +1143,7 @@ get_dev (char const *device, char const *mount_point, 
char const *file,
           affirm (!"bad field_type");
         }
 
-      switch (columns[col]->field)
+      switch (table.columns[col]->field)
         {
         case SOURCE_FIELD:
           cell = xstrdup (dev_name);
@@ -1227,8 +1240,8 @@ get_dev (char const *device, char const *mount_point, 
char const *file,
 
       replace_problematic_chars (cell);
       int cell_width = mbswidth (cell, MBSWIDTH_FLAGS);
-      columns[col]->width = MAX (columns[col]->width, cell_width);
-      table[nrows - 1][col] = cell;
+      table.columns[col]->width = MAX (table.columns[col]->width, cell_width);
+      table.rows[table.nrows - 1][col] = cell;
     }
   free (dev_name);
 }
-- 
2.56.0


Reply via email to