for (i = 0; i < ULONG_MAX; i++)
{
char suffix[INT_BUFSIZE_BOUND (i) + 1];
- char *name;
suffix[0] = '_';
- if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
- NOT_REACHED ();
+ str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1);
- name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
+ char *name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
if (var_name_is_insertable (dict, name))
{
free (root);
else
{
suffix[0] = '_';
- str_format_26adic (trial, true, &suffix[1], sizeof suffix - 1);
+ str_format_26adic__ (trial, true, &suffix[1], sizeof suffix - 1);
}
/* Set name. */
#include "spreadsheet-reader.h"
-#include <libpspp/assertion.h>
-#include "gnumeric-reader.h"
-#include "ods-reader.h"
-
-#include <libpspp/str.h>
#include <stdio.h>
#include <string.h>
-#include <gl/xalloc.h>
-#include <gl/c-xvasprintf.h>
#include <stdlib.h>
+#include "data/gnumeric-reader.h"
+#include "data/ods-reader.h"
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
+#include "gl/c-xvasprintf.h"
+
struct spreadsheet *
spreadsheet_ref (struct spreadsheet *s)
{
}
-#define RADIX 26
-
-static void
-reverse (char *s, int len)
-{
- int i;
- for (i = 0; i < len / 2; ++i)
- {
- char tmp = s[len - i - 1];
- s[len - i -1] = s[i];
- s[i] = tmp;
- }
-}
-
-
-/* Convert a string, which is an integer encoded in base26
- IE, A=0, B=1, ... Z=25 to the integer it represents.
- ... except that in this scheme, digits with an exponent
- greater than 1 are implicitly incremented by 1, so
- AA = 0 + 1*26, AB = 1 + 1*26,
- ABC = 2 + 2*26 + 1*26^2 ....
- On error, this function returns -1
-*/
-int
-ps26_to_int (const char *str)
-{
- int i;
- int multiplier = 1;
- int result = 0;
- int len = strlen (str);
-
- for (i = len - 1 ; i >= 0; --i)
- {
- char c = str[i];
- if (c < 'A' || c > 'Z')
- return -1;
- int mantissa = (c - 'A');
-
- assert (mantissa >= 0);
- assert (mantissa < RADIX);
-
- if (i != len - 1)
- mantissa++;
-
- result += mantissa * multiplier;
- multiplier *= RADIX;
- }
-
- return result;
-}
-
-/* Convert an integer, which must be non-negative,
- to pseudo base 26.
- The caller must free the return value when no longer required. */
-char *
-int_to_ps26 (int i)
-{
- char *ret = NULL;
-
- int lower = 0;
- long long int base = RADIX;
- int exp = 1;
-
- if (i < 0)
- return NULL;
-
- while (i > lower + base - 1)
- {
- lower += base;
- base *= RADIX;
- assert (base > 0);
- exp++;
- }
-
- i -= lower;
- i += base;
-
- ret = xmalloc (exp + 1);
-
- exp = 0;
- do
- {
- ret[exp++] = (i % RADIX) + 'A';
- i /= RADIX;
- }
- while (i > 1);
-
- ret[exp]='\0';
-
- reverse (ret, exp);
- return ret;
-}
-
-
char *
create_cell_ref (int col0, int row0)
{
- char *cs0 ;
- char *s ;
-
- if (col0 < 0) return NULL;
- if (row0 < 0) return NULL;
-
- cs0 = int_to_ps26 (col0);
- s = c_xasprintf ("%s%d", cs0, row0 + 1);
+ if (col0 < 0 || row0 < 0)
+ return NULL;
- free (cs0);
+ char s[F26ADIC_STRLEN_MAX + INT_STRLEN_BOUND (row0) + 1];
+ str_format_26adic (col0 + 1, true, s, sizeof s);
+ size_t len = strlen (s);
+ snprintf (s + len, sizeof s - len, "%d", row0 + 1);
- return s;
+ return xstrdup (s);
}
char *
if (n != 4)
return false;
- str_uppercase (startcol);
- *col0 = ps26_to_int (startcol);
- str_uppercase (stopcol);
- *coli = ps26_to_int (stopcol);
+ *col0 = str_parse_26adic (startcol);
+ *coli = str_parse_26adic (stopcol);
*row0 = startrow - 1;
*rowi = stoprow - 1 ;
int asw ; /* The width of string variables in the created dictionary */
};
-int ps26_to_int (const char *str);
-char * int_to_ps26 (int);
bool convert_cell_ref (const char *ref,
int *col0, int *row0,
#include <stdlib.h>
#include <unistr.h>
+#include "libpspp/assertion.h"
#include "libpspp/cast.h"
#include "libpspp/i18n.h"
#include "libpspp/message.h"
which has room for SIZE bytes. Uses uppercase if UPPERCASE is
true, otherwise lowercase, Returns true if successful, false
if NUMBER, plus a trailing null, is too large to fit in the
- available space.
+ available space. If SIZE is at least F26ADIC_STRLEN_MAX + 1,
+ the number is guaranteed to fit. Even if the number doesn't
+ fit, if SIZE > 0, the characters that do fit, if any, will be
+ null-terminated.
26-adic notation is "spreadsheet column numbering": 1 = A, 2 =
- B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ...
+ B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ... Zero is
+ the empty string.
26-adic notation is the special case of a k-adic numeration
system (aka bijective base-k numeration) with k=26. In k-adic
For more information, see
http://en.wikipedia.org/wiki/Bijective_numeration. */
bool
-str_format_26adic (unsigned long int number, bool uppercase,
- char buffer[], size_t size)
+str_format_26adic__ (unsigned long int number, bool uppercase,
+ char buffer[], size_t size)
{
const char *alphabet
= uppercase ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "abcdefghijklmnopqrstuvwxyz";
return false;
}
+/* Like str_format_26adic__(), but SIZE must be big enough that it cannot
+ fail. */
+void
+str_format_26adic (unsigned long int number, bool uppercase,
+ char buffer[], size_t size)
+{
+ assert (size >= F26ADIC_STRLEN_MAX + 1);
+ if (!str_format_26adic__ (number, uppercase, buffer, size))
+ NOT_REACHED ();
+}
+
+/* Returns the value of 26-adic string STR. See str_format_26adic() for a
+ definition of 26-adic.
+
+ On error, this function returns -1. */
+int
+str_parse_26adic (const char *str)
+{
+ enum { RADIX = 26 };
+
+ int multiplier = 1;
+ int result = 0;
+
+ size_t len = strlen (str);
+ for (size_t i = 0; i < len; i++)
+ {
+ if (result >= INT_MAX / RADIX)
+ return -1;
+
+ char c = str[len - i - 1];
+ int digit = (c >= 'A' && c <= 'Z' ? c - 'A'
+ : c >= 'a' && c <= 'z' ? c - 'a'
+ : -1);
+ if (digit < 0)
+ return -1;
+ assert (digit >= 0 && digit < RADIX);
+
+ result += (digit + (i > 0)) * multiplier;
+ multiplier *= RADIX;
+ }
+
+ return result;
+}
+
/* Copies IN to buffer OUT with size OUT_SIZE, appending a null terminator. If
IN is too long for OUT, or if IN contains a new-line, replaces the tail with
"...".
#define str_h 1
#include <assert.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include "xstrndup.h"
#include "xvasprintf.h"
+#include "gl/verify.h"
#include "gl/xalloc.h"
\f
/* Miscellaneous. */
void str_uppercase (char *);
void str_lowercase (char *);
-bool str_format_26adic (unsigned long int number, bool uppercase,
- char buffer[], size_t);
+/* Maximum number of digits needed to express ULONG_MAX in 26-adic notation. */
+#define F26ADIC_STRLEN_MAX 14
+verify (ULONG_MAX <= UINT64_MAX);
+
+bool str_format_26adic__ (unsigned long int number, bool uppercase,
+ char buffer[], size_t);
+void str_format_26adic (unsigned long int number, bool uppercase,
+ char buffer[], size_t);
+int str_parse_26adic (const char *str);
void str_ellipsize (struct substring in, char *out, size_t out_size);
ds_put_format (s, "%zu", f->idx + 1);
else
{
- char text[INT_BUFSIZE_BOUND (size_t)];
+ char text[F26ADIC_STRLEN_MAX + 1];
str_format_26adic (f->idx + 1, false, text, sizeof text);
ds_put_cstr (s, text);
}
#include "psppire-import-spreadsheet.h"
#include "builder-wrapper.h"
+#include "libpspp/assertion.h"
#include "libpspp/misc.h"
#include "psppire-spreadsheet-model.h"
#include "psppire-spreadsheet-data-model.h"
static void
set_column_header_label (GtkWidget *button, int i, gpointer user_data)
{
- gchar *x = int_to_ps26 (i);
+ char x[F26ADIC_STRLEN_MAX + 1];
+ str_format_26adic (i + 1, true, x, sizeof x);
gtk_button_set_label (GTK_BUTTON (button), x);
- g_free (x);
}
static void do_selection_update (PsppireImportAssistant *ia);
column_output (GtkSpinButton *sb, gpointer unused)
{
gint value = gtk_spin_button_get_value_as_int (sb);
- char *text = int_to_ps26 (value);
- if (text == NULL)
+ if (value < 0)
return FALSE;
+ char text[F26ADIC_STRLEN_MAX + 1];
+ str_format_26adic (value + 1, true, text, sizeof text);
gtk_entry_set_text (GTK_ENTRY (sb), text);
- free (text);
return TRUE;
}
/* Interprets the SBs text as 1 based instead of zero based. */
static gint
-row_input (GtkSpinButton *sb, gpointer new_value, gpointer unused)
+row_input (GtkSpinButton *sb, gdouble *new_value, gpointer unused)
{
const char *text = gtk_entry_get_text (GTK_ENTRY (sb));
gdouble value = g_strtod (text, NULL) - 1;
if (value < 0)
return FALSE;
- memcpy (new_value, &value, sizeof (value));
+ *new_value = value;
return TRUE;
}
/* Interprets the SBs text of the form A, B, C etc and
sets NEW_VALUE as a double. */
static gint
-column_input (GtkSpinButton *sb, gpointer new_value, gpointer unused)
+column_input (GtkSpinButton *sb, gdouble *new_value, gpointer unused)
{
const char *text = gtk_entry_get_text (GTK_ENTRY (sb));
- double value = ps26_to_int (text);
+ double value = str_parse_26adic (text);
if (value < 0)
return FALSE;
- memcpy (new_value, &value, sizeof (value));
+ *new_value = value;
return TRUE;
}
static void
check_26adic (unsigned long int number, const char *expected_string)
{
- char string[8];
+ char string[F26ADIC_STRLEN_MAX + 1];
str_format_26adic (number, true, string, sizeof string);
if (strcmp (string, expected_string))
{
s = &string_table[idx];
if (*s == NULL)
{
- *s = xmalloc (16);
- str_format_26adic (idx + 1, true, *s, 16);
+ size_t size = F26ADIC_STRLEN_MAX + 1;
+ *s = xmalloc (size);
+ str_format_26adic (idx + 1, true, *s, size);
}
return *s;
}
s = &string_table[value];
if (*s == NULL)
{
- *s = xmalloc (16);
- str_format_26adic (value + 1, true, *s, 16);
+ size_t size = F26ADIC_STRLEN_MAX + 1;
+ *s = xmalloc (size);
+ str_format_26adic (value + 1, true, *s, size);
}
return *s;
}