Gnulib does not maintain a stable API or ABI, so it is possible that
PSPP will not work with older or newer versions of Gnulib.
- commit 392f10a02b1effd254f3a751e42daccf929c3efa
- Author: John Darrington <john@darrington.wattle.id.au>
- Date: Sun Jul 29 00:30:48 2012 +0200
+ commit f022473fdaf724d84817c4003120b9a38fbf884b
+ Author: Ben Pfaff <blp@cs.stanford.edu>
+ Date: Tue Dec 18 21:06:17 2012 -0800
+
+ New 'c-*printf' modules for formatted output in C locale.
- clean-temp: Fix memory leak.
-
To clone Gnulib into a directory named "gnulib" using Git, and then
check out this particular commit, run these commands:
GNULIB_MODULES = \
assert \
byteswap \
+ c-snprintf \
c-strcase \
c-strcasestr \
c-ctype \
c-strtod \
+ c-xvasprintf \
clean-temp \
close \
configmake \
sys_stat \
tempname \
trunc \
+ unicase/u8-casecmp \
+ unicase/u8-casefold \
+ unicase/u8-tolower \
+ unicase/u8-toupper \
unictype/ctype-print \
unictype/property-id-continue \
unictype/property-id-start \
unigbrk/uc-is-grapheme-break \
unilbrk/u8-possible-linebreaks \
+ uninorm/nfkd \
unistd \
unistr/u8-check \
unistr/u8-cpy \
[/[@var{line_no}] @var{arg}@dots{}]
@var{arg} takes one of the following forms:
- '@var{string}' [@var{start}-@var{end}]
+ '@var{string}' [@var{start}]
@var{var_list} @var{start}-@var{end} [@var{type_spec}]
@var{var_list} (@var{fortran_spec})
@var{var_list} *
be specified using multiple slashes with the intended output for a line
following its respective slash.
-Literal strings may be printed. Specify the string itself. Optionally
-the string may be followed by a column number or range of column
-numbers, specifying the location on the line for the string to be
-printed. Otherwise, the string will be printed at the current position
-on the line.
+Literal strings may be printed. Specify the string itself.
+Optionally the string may be followed by a column number, specifying
+the column on the line where the string should start. Otherwise, the
+string will be printed at the current position on the line.
Variables to be printed can be specified in the same ways as available
for @cmd{DATA LIST FIXED} (@pxref{DATA LIST FIXED}). In addition, a
+#include <config.h>
#include <glib.h>
#include <gtk/gtk.h>
+#include <config.h>
#include <gladeui/glade.h>
#include <gtk/gtk.h>
+#include <config.h>
#include <glib.h>
#include <gtk/gtk.h>
+#include <config.h>
#include <glib.h>
#include <gtk/gtk.h>
# German translation for PSPP
# Copyright (C) 2012 Free Software Foundation, Inc.
# This file is distributed under the same license as the pspp package.
-# Matthias Keil <matthias.keil@uni-jena.de>, 2012.
+# Matthias Keil <matthias.keil@ymail.com>, - 2012
+# Stefan Grotz <stefan.grotz@uni-jena.de>, 2012 -
#
msgid ""
msgstr ""
"Project-Id-Version: pspp 0.7.9\n"
"Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
"POT-Creation-Date: 2012-02-03 19:12-0800\n"
-"PO-Revision-Date: 2012-02-29 10:29+0100\n"
-"Last-Translator: Matthias Keil <matthias.keil@uni-jena.de>\n"
+"PO-Revision-Date: 2012-12-17 19:01+0100\n"
+"Last-Translator: Matthias Keil <matthias.keil@ymail.com>\n"
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
-"Language: \n"
+"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-"X-Poedit-Language: German\n"
-"X-Poedit-Country: GERMANY\n"
-"X-Poedit-SourceCharset: utf-8\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Generator: Poedit 1.5.4\n"
#: src/ui/gui/helper.c:153
msgid "Sorry. The help system hasn't yet been implemented."
-msgstr ""
+msgstr "Entschuldigung. Das Hilfesystem wurde noch nicht implementiert. "
#: src/ui/gui/psppire-buttonbox.c:329 src/ui/gui/psppire-buttonbox.c:487
msgid "Continue"
#: src/data/calendar.c:100
#, c-format
msgid "Month %d is not in acceptable range of 0 to 13."
-msgstr ""
+msgstr "Der Monat %d ist nicht im akzeptierten Bereich von 0 bis 13."
#: src/data/calendar.c:110
#, c-format
msgid "Day %d is not in acceptable range of 0 to 31."
-msgstr ""
+msgstr "Der Tag %d ist nicht im akzeptierten Bereich von 0 bis 31"
#: src/data/calendar.c:119
#, c-format
msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
-msgstr ""
+msgstr "Das Datum %04d-%d-%d ist vor dem frühsten akzeptierten Datum 1582-10-15."
#: src/data/casereader-filter.c:221
msgid "At least one case in the data read had a weight value that was user-missing, system-missing, zero, or negative. These case(s) were ignored."
#. that identify types of files.
#: src/data/csv-file-writer.c:152
msgid "CSV file"
-msgstr ""
+msgstr "CSV Datei"
#: src/data/csv-file-writer.c:161 src/data/sys-file-writer.c:225
#, c-format
#: src/data/data-in.c:391
msgid "Invalid numeric syntax."
-msgstr ""
+msgstr "Ungültige numerische Syntax."
#: src/data/data-in.c:399 src/data/data-in.c:570
msgid "Too-large number set to system-missing."
#: src/data/data-in.c:782
#, c-format
msgid "Day (%ld) must be between 1 and 31."
-msgstr ""
+msgstr "Tag (%ld) muss zwischen 1 und 31 liegen."
#: src/data/data-in.c:827
msgid "Delimiter expected between fields in date."
#: src/data/data-in.c:901
msgid "Unrecognized month format. Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names."
-msgstr ""
+msgstr "Unbekanntes Monatsformat. Monate müssen mit arabischen oder romanischen Zahlen oder mindestens den ersten 3 Buchstaben ihrer englischen Namen bezeichnet werden."
#: src/data/data-in.c:928
#, c-format
msgid "Year (%ld) must be between 1582 and 19999."
-msgstr ""
+msgstr "Jahr (%ld) muss zwischen 1582 und 19999 liegen."
#: src/data/data-in.c:939
#, c-format
#: src/data/data-in.c:1000
#, c-format
msgid "Week (%ld) must be between 1 and 53."
-msgstr ""
+msgstr "Woche (%ld) muss zwischen 1 und 53 liegen."
#: src/data/data-in.c:1012
msgid "Delimiter expected between fields in time."
#: src/data/data-in.c:1032
#, c-format
msgid "Minute (%ld) must be between 0 and 59."
-msgstr ""
+msgstr "Minute (%ld) muss zwischen 0 und 59 liegen."
#: src/data/data-in.c:1070
msgid "Unrecognized weekday name. At least the first two letters of an English weekday name must be specified."
#: src/data/data-out.c:546
#, c-format
msgid "Weekday number %f is not between 1 and 7."
-msgstr ""
+msgstr "Die Nummer des Wochentages %f ist nicht zwischen 1 und 7."
#: src/data/data-out.c:571
#, c-format
msgid "Month number %f is not between 1 and 12."
-msgstr ""
+msgstr "Die Nummer des Monats %f ist nicht zwischen 1 und 12."
#: src/data/dataset-reader.c:54
#, c-format
#. messages in fh_lock() that identify types of files.
#: src/data/dataset-writer.c:66 src/language/data-io/file-handle.q:187
msgid "dataset"
-msgstr ""
+msgstr "Datensatz"
#: src/data/dict-class.c:52
msgid "ordinary"
#: src/data/file-handle-def.c:254
msgid "active dataset"
-msgstr ""
+msgstr "aktiver Datensatz"
#: src/data/file-handle-def.c:465
#, c-format
#: src/data/por-file-reader.c:386
msgid "Number expected."
-msgstr ""
+msgstr "Zahl erwartet."
#: src/data/por-file-reader.c:414
msgid "Missing numeric terminator."
#: src/data/sys-file-reader.c:467
#, c-format
msgid "Weighting variable must be numeric (not string variable `%s')."
-msgstr ""
+msgstr "Gewichtungsvariable muss numerisch sein. ( nicht Stringvariable `%s')."
#: src/data/sys-file-reader.c:502
#, c-format
#: src/data/sys-file-reader.c:959
#, c-format
msgid "Invalid variable name `%s'."
-msgstr ""
+msgstr "Ungültiges Variablenlabel `%s'."
#: src/data/sys-file-reader.c:967
#, c-format
#: src/data/sys-file-reader.c:2541
#, c-format
msgid "System error: %s."
-msgstr ""
+msgstr "System Fehler: %s."
#: src/data/sys-file-reader.c:2543
msgid "Unexpected end of file."
#: src/language/utilities/set.q:220
#, c-format
msgid "%s is not yet implemented."
-msgstr ""
+msgstr "%s ist noch nicht implementiert."
#: src/language/command.c:201
#, c-format
#: src/language/lexer/lexer.c:398
msgid "Syntax error at end of input"
-msgstr ""
+msgstr "Syntax Fehler am ende der Eingabe"
#: src/language/lexer/lexer.c:419 src/language/xforms/select-if.c:60
#: src/language/stats/autorecode.c:206 src/language/stats/npar.c:478
#: src/language/lexer/lexer.c:1300
msgid "Syntax error at end of command"
-msgstr ""
+msgstr "Syntax Fehler am Ende des Befehls"
#: src/language/lexer/lexer.c:1309
#, c-format
msgid "Syntax error at `%s'"
-msgstr ""
+msgstr "Syntax Fehler bei `%s'"
#: src/language/lexer/lexer.c:1312
msgid "Syntax error"
-msgstr ""
+msgstr "Syntax Fehler"
#: src/language/lexer/lexer.c:1476
#, c-format
#: src/language/lexer/lexer.c:1508
msgid "Unexpected `.' in middle of command"
-msgstr ""
+msgstr "Unerwartetes `.' in der Mitte des Befehls."
#: src/language/lexer/lexer.c:1514
#, c-format
#: src/language/data-io/placement-parser.c:225
#, c-format
msgid "Unknown format type `%s'."
-msgstr ""
+msgstr "Unbekannter Formattyp `%s'."
#: src/language/lexer/format-parser.c:131
msgid "expecting format type"
#: src/language/lexer/variable-parser.c:77
#, c-format
msgid "%s is not a variable name."
-msgstr ""
+msgstr "%s ist kein Variablenlabel"
#: src/language/lexer/variable-parser.c:180
#, c-format
msgid "%s is not a numeric variable. It will not be included in the variable list."
-msgstr ""
+msgstr "%s ist keine numerische Variable. Es wird nicht in die Variablenliste eingefügt."
#: src/language/lexer/variable-parser.c:183
#, c-format
msgid "%s is not a string variable. It will not be included in the variable list."
-msgstr ""
+msgstr "%s ist keine String-Variable. Es wird nicht in die Variablenliste eingefügt."
#: src/language/lexer/variable-parser.c:187
#, c-format
#: src/language/lexer/variable-parser.c:404
#, c-format
msgid "Variable %s appears twice in variable list."
-msgstr ""
+msgstr "Variable %s taucht zwei Mal in der Variablenliste auf."
#: src/language/lexer/variable-parser.c:315
#, c-format
#: src/language/xforms/select-if.c:115
msgid "The filter variable must be numeric."
-msgstr ""
+msgstr "Die Filtervariable muss numerisch sein."
#: src/language/xforms/select-if.c:121
msgid "The filter variable may not be scratch."
#: src/language/dictionary/mrsets.c:550
msgid "Details"
-msgstr ""
+msgstr "Details"
#: src/language/dictionary/mrsets.c:564
msgid "Multiple dichotomy set"
#: src/language/dictionary/numeric.c:87 src/language/dictionary/numeric.c:157
#, c-format
msgid "There is already a variable named %s."
-msgstr ""
+msgstr "Es existiert bereits eine Variable namens %s."
#: src/language/dictionary/numeric.c:142
#, c-format
#: src/language/dictionary/sys-file-info.c:100
msgid "No label."
-msgstr ""
+msgstr "Kein Label."
#: src/language/dictionary/sys-file-info.c:103
msgid "Created:"
#: src/language/dictionary/sys-file-info.c:133
msgid "Not weighted."
-msgstr ""
+msgstr "Nicht gewichtet."
#: src/language/dictionary/sys-file-info.c:135
msgid "Mode:"
#: src/language/dictionary/sys-file-info.c:137
msgid "on"
-msgstr ""
+msgstr "an"
#: src/language/dictionary/sys-file-info.c:137
msgid "off"
-msgstr ""
+msgstr "aus"
#: src/language/dictionary/sys-file-info.c:140
msgid "Charset:"
#: src/language/dictionary/sys-file-info.c:525
msgid "Missing Values: "
-msgstr ""
+msgstr "Fehlende Werte:"
#: src/language/dictionary/sys-file-info.c:624
msgid "No vectors defined."
#: src/language/dictionary/vector.c:171
#, c-format
msgid "%s is an existing variable name."
-msgstr ""
+msgstr "%s ist ein existierendes Variablenlabel"
#: src/language/dictionary/variable-display.c:120
msgid "Variable display width must be a positive integer."
#: src/language/stats/glm.c:167
msgid "Multivariate analysis is not yet implemented"
-msgstr ""
+msgstr "Multivariate Analysen sind noch nicht implementiert"
#: src/language/stats/glm.c:272
msgid "Only types 1, 2 & 3 sums of squares are currently implemented"
#: src/language/stats/glm.c:844
msgid "Error"
-msgstr ""
+msgstr "Fehler"
#: src/language/stats/glm.c:860
msgid "Corrected Total"
#: src/language/stats/means.c:1066 src/language/stats/crosstabs.q:839
#: src/language/stats/examine.q:1178 src/language/stats/frequencies.q:823
msgid "Percent"
-msgstr ""
+msgstr "Prozent"
#: src/language/stats/means.c:1096 src/language/stats/means.c:1105
#: src/language/stats/means.c:1114
#: src/language/stats/roc.c:1068
msgid "Unweighted"
-msgstr ""
+msgstr "ungewichtet"
#: src/language/stats/roc.c:1069
msgid "Weighted"
-msgstr ""
+msgstr "gewichtet"
#: src/language/stats/roc.c:1073
msgid "Valid N (listwise)"
#: src/language/data-io/dataset.c:63
#, c-format
msgid "There is no dataset named %s."
-msgstr ""
+msgstr "Es gibt keinen Datensatz namens %s."
#: src/language/data-io/dataset.c:257
msgid "Dataset"
-msgstr ""
+msgstr "Datensatz"
#: src/language/data-io/dataset.c:265
msgid "unnamed dataset"
-msgstr ""
+msgstr "unbenannter Datensatz"
#: src/language/data-io/dataset.c:269
msgid "(active dataset)"
-msgstr ""
+msgstr "(aktiver Datensatz)"
#: src/language/data-io/get-data.c:99
#, c-format
#: src/libpspp/message.c:85
msgid "error"
-msgstr ""
+msgstr "Fehler"
#: src/libpspp/message.c:87
msgid "warning"
#: src/output/charts/plot-hist-cairo.c:112
#: src/language/stats/frequencies.q:822
msgid "Frequency"
-msgstr ""
+msgstr "Häufigkeit"
#: src/output/charts/roc-chart-cairo.c:36 src/ui/gui/roc.ui:7
msgid "ROC Curve"
#. translation to your language.
#: src/ui/gui/help-menu.c:76
msgid "translator-credits"
-msgstr "Matthias Keil"
+msgstr "Matthias KeilStefan Grotz"
#: src/ui/gui/help-menu.c:106
#, c-format
#: src/ui/gui/psppire-dialog-action-var-info.c:124
#, c-format
msgid "Missing Values: %s\n"
-msgstr ""
+msgstr "Fehlende Werte: %s\n"
#: src/ui/gui/psppire-dialog-action-var-info.c:128
#, c-format
#: src/ui/gui/psppire-dialog-action-var-info.c:141
msgid "Value Labels:\n"
-msgstr ""
+msgstr "Wertelabel:\n"
#: src/ui/gui/psppire-dialog-action-var-info.c:150
#, c-format
#: src/ui/gui/text-data-import-dialog.c:453
#, c-format
msgid "Could not open `%s': %s"
-msgstr ""
+msgstr " `%s': %s konnte nicht geöffnet werden"
#: src/ui/gui/text-data-import-dialog.c:469
#, c-format
#: src/language/utilities/set.q:156 src/language/utilities/set.q:163
#, c-format
msgid "%s must be at least 1."
-msgstr ""
+msgstr "%s muss mindestens 1 sein."
#: src/language/utilities/set.q:170 src/language/data-io/file-handle.q:102
#, c-format
msgid "%s must not be negative."
-msgstr ""
+msgstr "%s darf nicht negativ sein."
#: src/language/utilities/set.q:189
msgid "WORKSPACE must be at least 1MB"
#: src/language/utilities/set.q:870
#, c-format
msgid "%s is %s."
-msgstr ""
+msgstr "%s ist %s."
#: src/language/utilities/set.q:973
#, c-format
#: src/language/stats/crosstabs.q:826
msgid "Summary."
-msgstr ""
+msgstr "Zusammenfassung."
#. TRANSLATORS: The %s here describes a crosstabulation. It takes the
#. form "var1 * var2 * var3 * ...".
#: src/language/stats/frequencies.q:381
msgid "Bar charts are not implemented."
-msgstr ""
+msgstr "Balkendiagramme sind noch nicht implementiert."
#: src/language/stats/frequencies.q:398
#, c-format
#: src/language/stats/frequencies.q:820
msgid "Value Label"
-msgstr ""
+msgstr "Wertelabel"
#: src/language/stats/frequencies.q:824
msgid "Valid Percent"
-msgstr ""
+msgstr "Gültige Prozente"
#: src/language/stats/frequencies.q:825
msgid "Cum Percent"
-msgstr ""
+msgstr "Kumulierte Prozente"
#: src/language/stats/frequencies.q:1015
#, c-format
#: src/language/stats/regression.q:938
msgid "REGRESSION requires numeric variables."
-msgstr ""
+msgstr "REGRESSION benötigt numerische Variablen."
#: src/language/stats/regression.q:1013
msgid "No valid data found. This command was skipped."
#: src/ui/gui/var-sheet-dialogs.ui:419 src/ui/gui/var-sheet-dialogs.ui:610
msgid "Value Labels"
-msgstr "Wertelabels"
+msgstr "Wertelabel"
#: src/ui/gui/var-sheet-dialogs.ui:516
msgid "Value Label:"
#: src/ui/gui/data-editor.ui:140
msgid "Jump to a case in the data sheet"
-msgstr ""
+msgstr "Gehe zu Fall"
#: src/ui/gui/data-editor.ui:166
msgid "Cl_ear Variables"
#: src/ui/gui/data-editor.ui:176
msgid "Delete the cases at the selected position(s)"
-msgstr ""
+msgstr "Lösche Fälle in den/der ausgewählten Position(en)"
#: src/ui/gui/data-editor.ui:183
msgid "_Find..."
#: src/ui/gui/data-editor.ui:268
msgid "Split the active dataset"
-msgstr ""
+msgstr "Datei aufteilen"
#: src/ui/gui/data-editor.ui:275
msgid "Select _Cases..."
#: src/ui/gui/data-editor.ui:502
msgid "Jump to variable"
-msgstr ""
+msgstr "Zu Variable springen"
#: src/ui/gui/data-editor.ui:509
msgid "Data File _Comments..."
#include "libpspp/array.h"
#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
#include "gl/xalloc.h"
{
struct attribute *attr;
HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
- hash_case_string (name, 0), &set->map)
- if (!strcasecmp (attribute_get_name (attr), name))
+ utf8_hash_case_string (name, 0), &set->map)
+ if (!utf8_strcasecmp (attribute_get_name (attr), name))
break;
return attr;
}
{
const char *name = attribute_get_name (attr);
assert (attrset_lookup (set, name) == NULL);
- hmap_insert (&set->map, &attr->node, hash_case_string (name, 0));
+ hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
}
/* Deletes any attribute from SET that matches NAME
/* PSPP - a program for statistical analysis.
- Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
else
{
char s[MAX (DBL_STRLEN_BOUND, 128)];
+ char *cp;
switch (cv->format.type)
{
case FMT_WKDAY:
case FMT_MONTH:
dtoastr (s, sizeof s, 0, 0, value->f);
- if (w->opts.decimal != '.')
- {
- char *cp = strchr (s, '.');
- if (cp != NULL)
- *cp = w->opts.decimal;
- }
+ cp = strpbrk (s, ".,");
+ if (cp != NULL)
+ *cp = w->opts.decimal;
break;
case FMT_DATE:
*cp++ = ss_get_byte (&i->input);
*cp = '\0';
- *time += strtod (buf, NULL);
+ *time += c_strtod (buf, NULL);
return NULL;
}
#include "libpspp/str.h"
#include "gl/minmax.h"
+#include "gl/c-snprintf.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
char buf[128];
number = fabs (round (number));
if (number < power10 (format->w)
- && sprintf (buf, "%0*.0f", format->w, number) == format->w)
+ && c_snprintf (buf, 128, "%0*.0f", format->w, number) == format->w)
memcpy (output, buf, format->w);
else
output_overflow (format, output);
if (input->f == SYSMIS)
output_missing (format, output);
else if (fabs (number) < power10 (format->w)
- && sprintf (buf, "%0*.0f", format->w,
+ && c_snprintf (buf, 128, "%0*.0f", format->w,
fabs (round (number))) == format->w)
{
if (number < 0 && strspn (buf, "0") < format->w)
if (number < 0)
*p++ = '-';
number = fabs (number);
- p += sprintf (p, "%*.0f", count, floor (number / 60. / 60. / 24.));
+ p += c_snprintf (p, 64, "%*.0f", count, floor (number / 60. / 60. / 24.));
number = fmod (number, 60. * 60. * 24.);
break;
case 'H':
if (number < 0)
*p++ = '-';
number = fabs (number);
- p += sprintf (p, "%0*.0f", count, floor (number / 60. / 60.));
+ p += c_snprintf (p, 64, "%0*.0f", count, floor (number / 60. / 60.));
number = fmod (number, 60. * 60.);
break;
case 'M':
{
int d = MIN (format->d, excess_width - 4);
int w = d + 3;
- sprintf (p, ":%0*.*f", w, d, number);
+ c_snprintf (p, 64, ":%0*.*f", w, d, number);
if (settings_get_decimal_char (FMT_F) != '.')
{
char *cp = strchr (p, '.');
/* Figure out number of characters we can use for the fraction,
if any. (If that turns out to be 1, then we'll output a
decimal point without any digits following; that's what the
- # flag does in the call to sprintf, below.) */
+ # flag does in the call to c_snprintf, below.) */
fraction_width = MIN (MIN (format->d + 1, format->w - width), 16);
if (format->type != FMT_E && fraction_width == 1)
fraction_width = 0;
if (add_affixes)
p = stpcpy (p, style->prefix.s);
if (fraction_width > 0)
- sprintf (p, "%#.*E", fraction_width - 1, fabs (number));
+ c_snprintf (p, 64, "%#.*E", fraction_width - 1, fabs (number));
else
- sprintf (p, "%.0E", fabs (number));
+ c_snprintf (p, 64, "%.0E", fabs (number));
/* The C locale always uses a period `.' as a decimal point.
Translate to comma if necessary. */
We append ".00" to the integer representation because
round_up assumes that fractional digits are present. */
- sprintf (r->string, "%.0f.00", fabs (round (number)));
+ c_snprintf (r->string, 64, "%.0f.00", fabs (round (number)));
}
else
{
numbers does not hint how to do what we want, and it's
not obvious how to change their algorithms to do so. It
would also be a lot of work. */
- sprintf (r->string, "%.*f", max_decimals + 2, fabs (number));
+ c_snprintf (r->string, 64, "%.*f", max_decimals + 2, fabs (number));
if (!strcmp (r->string + strlen (r->string) - 2, "50"))
{
int binary_exponent, decimal_exponent, format_decimals;
decimal_exponent = binary_exponent * 3 / 10;
format_decimals = (DBL_DIG + 1) - decimal_exponent;
if (format_decimals > max_decimals + 2)
- sprintf (r->string, "%.*f", format_decimals, fabs (number));
+ c_snprintf (r->string, 64, "%.*f", format_decimals, fabs (number));
}
}
if (number != SYSMIS
&& number >= 0.
&& number < power10 (digits)
- && sprintf (decimal, "%0*.0f", digits, round (number)) == digits)
+ && c_snprintf (decimal, 64, "%0*.0f", digits, round (number)) == digits)
{
const char *src = decimal;
int i;
vardict->dict = d;
vardict->var = v;
hmap_insert (&d->name_map, &vardict->name_node,
- hash_case_string (var_get_name (v), 0));
+ utf8_hash_case_string (var_get_name (v), 0));
vardict->case_index = d->next_value_idx;
var_set_vardict (v, vardict);
struct vardict_info *vardict;
HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
- hash_case_string (name, 0), &d->name_map)
+ utf8_hash_case_string (name, 0), &d->name_map)
{
struct variable *var = vardict->var;
- if (!strcasecmp (var_get_name (var), name))
+ if (!utf8_strcasecmp (var_get_name (var), name))
return var;
}
struct vardict_info *vardict = var_get_vardict (v);
var_clear_vardict (v);
var_set_name (v, new_name);
- vardict->name_node.hash = hash_case_string (new_name, 0);
+ vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
var_set_vardict (v, vardict);
}
dict_rename_var (struct dictionary *d, struct variable *v,
const char *new_name)
{
- assert (!strcasecmp (var_get_name (v), new_name)
+ assert (!utf8_strcasecmp (var_get_name (v), new_name)
|| dict_lookup_var (d, new_name) == NULL);
unindex_var (d, var_get_vardict (v));
{
size_t i;
for (i = 0; i < d->vector_cnt; i++)
- if (!strcasecmp (vector_get_name (d->vector[i]), name))
+ if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
return d->vector[i];
return NULL;
}
size_t i;
for (i = 0; i < dict->n_mrsets; i++)
- if (!strcasecmp (name, dict->mrsets[i]->name))
+ if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
return i;
return SIZE_MAX;
struct file_handle *handle;
HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
- hash_case_string (id, 0), &named_handles)
- if (!strcasecmp (id, handle->id))
+ utf8_hash_case_string (id, 0), &named_handles)
+ if (!utf8_strcasecmp (id, handle->id))
{
return fh_ref (handle);
}
if (id != NULL)
{
hmap_insert (&named_handles, &handle->name_node,
- hash_case_string (handle->id, 0));
+ utf8_hash_case_string (handle->id, 0));
}
return handle;
#include "libpspp/misc.h"
#include "libpspp/str.h"
+#include "gl/c-strcase.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
int i;
for (i = 0; i < FMT_NUMBER_OF_FORMATS; i++)
- if (!strcasecmp (name, get_fmt_desc (i)->name))
+ if (!c_strcasecmp (name, get_fmt_desc (i)->name))
{
*type = i;
return true;
#include "libpspp/misc.h"
#include "gl/minmax.h"
+#include "gl/c-strtod.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
char *endptr;
errno = 0;
- v->f = strtod (text, &endptr);
+ v->f = c_strtod (text, &endptr);
if ( errno != 0 || endptr == text)
v->f = SYSMIS;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/misc.h"
#include "libpspp/str.h"
-#include "gl/xalloc.h"
+#include "gl/c-strcase.h"
#include "gl/minmax.h"
+#include "gl/xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
{
const char *dt = PQparameterStatus (r->conn, "integer_datetimes");
- r->integer_datetimes = ( 0 == strcasecmp (dt, "on"));
+ r->integer_datetimes = ( 0 == c_strcasecmp (dt, "on"));
}
#if USE_SSL
#include "libpspp/assertion.h"
#include "libpspp/cast.h"
#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
#include "libpspp/str.h"
#include "libpspp/hmapx.h"
if (old != NULL)
session_remove_dataset (s, old);
- hmapx_insert (&s->datasets, ds, hash_case_string (dataset_name (ds), 0));
+ hmapx_insert (&s->datasets, ds,
+ utf8_hash_case_string (dataset_name (ds), 0));
if (s->active == NULL)
s->active = ds;
struct hmapx_node *node;
struct dataset *ds;
- HMAPX_FOR_EACH_WITH_HASH (ds, node, hash_case_string (name, 0), &s->datasets)
- if (!strcasecmp (dataset_name (ds), name))
+ HMAPX_FOR_EACH_WITH_HASH (ds, node, utf8_hash_case_string (name, 0),
+ &s->datasets)
+ if (!utf8_strcasecmp (dataset_name (ds), name))
return node;
return NULL;
#include "libpspp/str.h"
#include "libpspp/stringi-set.h"
+#include "gl/c-strtod.h"
#include "gl/c-ctype.h"
#include "gl/inttostr.h"
#include "gl/localcharset.h"
mrset->width = width;
value_init (&mrset->counted, width);
if (width == 0)
- mrset->counted.f = strtod (counted, NULL);
+ mrset->counted.f = c_strtod (counted, NULL);
else
value_copy_str_rpad (&mrset->counted, width,
(const uint8_t *) counted, ' ');
if (record == NULL)
{
- /* Convert variable names to lowercase. */
+ /* There are no long variable names. Use the short variable names,
+ converted to lowercase, as the long variable names. */
size_t i;
for (i = 0; i < dict_get_var_cnt (dict); i++)
struct variable *var = dict_get_var (dict, i);
char *new_name;
- new_name = xstrdup (var_get_name (var));
- str_lowercase (new_name);
-
+ new_name = utf8_to_lower (var_get_name (var));
rename_var_and_save_short_names (dict, var, new_name);
-
free (new_name);
}
}
/* Identify any duplicates. */
- if (strcasecmp (var_get_short_name (var, 0), long_name)
+ if (utf8_strcasecmp (var_get_short_name (var, 0), long_name)
&& dict_lookup_var (dict, long_name) != NULL)
{
sys_warn (r, record->pos,
for (j = 0; j < mrset->n_vars; j++)
{
const char *short_name_utf8 = var_get_short_name (mrset->vars[j], 0);
+ char *lower_name_utf8 = utf8_to_lower (short_name_utf8);
char *short_name = recode_string (encoding, "UTF-8",
- short_name_utf8, -1);
- str_lowercase (short_name);
+ lower_name_utf8, -1);
ds_put_format (&s, " %s", short_name);
free (short_name);
+ free (lower_name_utf8);
}
ds_put_byte (&s, '\n');
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
}
}
+/* Returns true if VALUE, with the given WIDTH, is all spaces, false otherwise.
+ Returns false if VALUE is numeric. */
+bool
+value_is_spaces (const union value *value, int width)
+{
+ const uint8_t *s = value_str (value, width);
+ int i;
+
+ for (i = 0; i < width; i++)
+ if (s[i] != ' ')
+ return false;
+
+ return true;
+}
+
/* Returns true if resizing a value from OLD_WIDTH to NEW_WIDTH
actually changes anything, false otherwise. If false is
returned, calls to value_resize() with the specified
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
bool value_needs_resize (int old_width, int new_width);
void value_resize (union value *, int old_width, int new_width);
+bool value_is_spaces (const union value *, int width);
+
static inline void value_swap (union value *, union value *);
struct pool;
const struct variable *a = a_;
const struct variable *b = b_;
- return strcasecmp (a->name, b->name);
+ return utf8_strcasecmp (a->name, b->name);
}
/* A hsh_hash_func that hashes variable V based on its name. */
{
const struct variable *v = v_;
- return hash_case_string (v->name, 0);
+ return utf8_hash_case_string (v->name, 0);
}
/* A hsh_compare_func that orders pointers to variables A and B
struct variable *const *a = a_;
struct variable *const *b = b_;
- return strcasecmp (var_get_name (*a), var_get_name (*b));
+ return utf8_strcasecmp (var_get_name (*a), var_get_name (*b));
}
/* A hsh_compare_func that orders pointers to variables A and B
{
struct variable *const *v = v_;
- return hash_case_string (var_get_name (*v), 0);
+ return utf8_hash_case_string (var_get_name (*v), 0);
}
\f
/* Returns the type of variable V. */
for (i = old_cnt; i < var->short_name_cnt; i++)
var->short_names[i] = NULL;
}
- var->short_names[idx] = xstrdup (short_name);
- str_uppercase (var->short_names[idx]);
+ var->short_names[idx] = utf8_to_upper (short_name);
}
dict_var_changed (var);
/* PSPP - a program for statistical analysis.
- Copyright (C) 2006, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "data/dictionary.h"
#include "data/identifier.h"
#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
#include "libpspp/str.h"
#include "gl/xalloc.h"
struct vector *a = *pa;
struct vector *b = *pb;
- return strcasecmp (a->name, b->name);
+ return utf8_strcasecmp (a->name, b->name);
}
#include "libpspp/cast.h"
#include "libpspp/hash-functions.h"
#include "libpspp/hmap.h"
+#include "libpspp/i18n.h"
#include "libpspp/message.h"
#include "libpspp/str.h"
+#include "libpspp/misc.h"
#include "gl/ftoastr.h"
#include "gl/minmax.h"
static unsigned int
hash_dummy (const char *name, size_t name_len)
{
- return hash_case_bytes (name, name_len, 0);
+ return utf8_hash_case_bytes (name, name_len, 0);
}
static const struct dummy_var *
HMAP_FOR_EACH_WITH_HASH (dv, struct dummy_var, hmap_node,
hash_dummy (name, name_len), hmap)
- if (strcasecmp (dv->name, name))
+ if (utf8_strcasecmp (dv->name, name))
return dv;
return NULL;
{
char s[DBL_BUFSIZE_BOUND];
- dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
+ c_dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
add_replacement (dv, xstrdup (s), &allocated);
lex_get (lexer);
}
/* Variables. */
struct subcase by_vars; /* BY variables in this input file. */
struct subcase src, dst; /* Data to copy to output; where to put it. */
+ const struct missing_values **mv; /* Each variable's missing values. */
/* Input files. */
struct file_handle *handle; /* Input file handle. */
subcase_init_empty (&file->by_vars);
subcase_init_empty (&file->src);
subcase_init_empty (&file->dst);
+ file->mv = NULL;
file->handle = NULL;
file->dict = NULL;
file->reader = NULL;
size_t src_var_cnt = dict_get_var_cnt (file->dict);
size_t j;
+ file->mv = xnmalloc (src_var_cnt, sizeof *file->mv);
for (j = 0; j < src_var_cnt; j++)
{
struct variable *src_var = dict_get_var (file->dict, j);
var_get_name (src_var));
if (dst_var != NULL)
{
+ size_t n = subcase_get_n_fields (&file->src);
+ file->mv[n] = var_get_missing_values (src_var);
subcase_add_var (&file->src, src_var, SC_ASCEND);
subcase_add_var (&file->dst, dst_var, SC_ASCEND);
}
subcase_destroy (&file->by_vars);
subcase_destroy (&file->src);
subcase_destroy (&file->dst);
+ free (file->mv);
fh_unref (file->handle);
dict_destroy (file->dict);
casereader_destroy (file->reader);
static bool scan_table (struct comb_file *, union value by[]);
static struct ccase *create_output_case (const struct comb_proc *);
static void apply_case (const struct comb_file *, struct ccase *);
-static void apply_file_case_and_advance (struct comb_file *, struct ccase *,
- union value by[]);
+static void apply_nonmissing_case (const struct comb_file *, struct ccase *);
+static void advance_file (struct comb_file *, union value by[]);
static void output_case (struct comb_proc *, struct ccase *, union value by[]);
static void output_buffered_case (struct comb_proc *);
while (file->is_minimal)
{
struct ccase *output = create_output_case (proc);
- apply_file_case_and_advance (file, output, by);
+ apply_case (file, output);
+ advance_file (file, by);
output_case (proc, output, by);
}
}
if (file->type == COMB_FILE)
{
if (file->is_minimal)
- apply_file_case_and_advance (file, output, NULL);
+ {
+ apply_case (file, output);
+ advance_file (file, NULL);
+ }
}
else
{
for (first = &proc->files[0]; ; first++)
if (first->is_minimal)
break;
- apply_file_case_and_advance (first, output, by);
+ apply_case (first, output);
+ advance_file (first, by);
/* Read additional cases and update the output case from
them. (Don't update the output case from any duplicate
file < &proc->files[proc->n_files]; file++)
{
while (file->is_minimal)
- apply_file_case_and_advance (file, output, by);
+ {
+ apply_nonmissing_case (file, output);
+ advance_file (file, by);
+ }
}
casewriter_write (proc->output, output);
while (first->is_minimal)
{
output = create_output_case (proc);
- apply_file_case_and_advance (first, output, by);
+ apply_case (first, output);
+ advance_file (first, by);
casewriter_write (proc->output, output);
}
}
return output;
}
+static void
+mark_file_used (const struct comb_file *file, struct ccase *output)
+{
+ if (file->in_var != NULL)
+ case_data_rw (output, file->in_var)->f = true;
+}
+
/* Copies the data from FILE's case into output case OUTPUT.
If FILE has an IN variable, then it is set to 1 in OUTPUT. */
static void
apply_case (const struct comb_file *file, struct ccase *output)
{
subcase_copy (&file->src, file->data, &file->dst, output);
- if (file->in_var != NULL)
- case_data_rw (output, file->in_var)->f = true;
+ mark_file_used (file, output);
+}
+
+/* Copies the data from FILE's case into output case OUTPUT,
+ skipping values that are missing or all spaces.
+
+ If FILE has an IN variable, then it is set to 1 in OUTPUT. */
+static void
+apply_nonmissing_case (const struct comb_file *file, struct ccase *output)
+{
+ size_t i;
+
+ for (i = 0; i < subcase_get_n_fields (&file->src); i++)
+ {
+ const struct subcase_field *src_field = &file->src.fields[i];
+ const struct subcase_field *dst_field = &file->dst.fields[i];
+ const union value *src_value
+ = case_data_idx (file->data, src_field->case_index);
+ int width = src_field->width;
+
+ if (!mv_is_value_missing (file->mv[i], src_value, MV_ANY)
+ && !(width > 0 && value_is_spaces (src_value, width)))
+ value_copy (case_data_rw_idx (output, dst_field->case_index),
+ src_value, width);
+ }
+ mark_file_used (file, output);
}
-/* Like apply_case() above, but also advances FILE to its next
- case. Also, if BY is nonnull, then FILE's is_minimal member
- is updated based on whether the new case's BY values still
- match those in BY. */
+/* Advances FILE to its next case. If BY is nonnull, then FILE's is_minimal
+ member is updated based on whether the new case's BY values still match
+ those in BY. */
static void
-apply_file_case_and_advance (struct comb_file *file, struct ccase *output,
- union value by[])
+advance_file (struct comb_file *file, union value by[])
{
- apply_case (file, output);
case_unref (file->data);
file->data = casereader_read (file->reader);
if (by)
#include "libpspp/pool.h"
#include "libpspp/str.h"
+#include "gl/c-strcase.h"
#include "gl/xalloc.h"
#include "gl/xsize.h"
formats like those parsed by DATA LIST or PRINT. Returns true
only if successful.
+ The formats parsed are either input or output formats, according
+ to USE.
+
+ If USE is FMT_FOR_INPUT, then T, X, and / "formats" are parsed,
+ in addition to regular formats. If USE is FMT_FOR_OUTPUT, then
+ T and X "formats" are parsed but not /.
+
If successful, formats for VAR_CNT variables are stored in
*FORMATS, and the number of formats required is stored in
*FORMAT_CNT. *FORMAT_CNT may be greater than VAR_CNT because
{
new_formats = &f;
new_format_cnt = 1;
- if (lex_match (lexer, T_SLASH))
+ if (use == FMT_FOR_INPUT && lex_match (lexer, T_SLASH))
f.type = PRS_TYPE_NEW_REC;
else
{
if (!parse_abstract_format_specifier (lexer, type, &f.w, &f.d))
return false;
- if (!strcasecmp (type, "T"))
+ if (!c_strcasecmp (type, "T"))
f.type = PRS_TYPE_T;
- else if (!strcasecmp (type, "X"))
+ else if (!c_strcasecmp (type, "X"))
{
f.type = PRS_TYPE_X;
f.w = count;
}
}
-/* Parses a BASE-based column using LEXER. Returns true and
- stores a 1-based column number into *COLUMN if successful,
- otherwise emits an error message and returns false. */
-static bool
-parse_column (int value, int base, int *column)
+bool
+parse_column__ (int value, int base, int *column)
{
assert (base == 0 || base == 1);
*column = value - base + 1;
return true;
}
+/* Parses a BASE-based column using LEXER. Returns true and
+ stores a 1-based column number into *COLUMN if successful,
+ otherwise emits an error message and returns false.
+
+ If BASE is 0, zero-based column numbers are parsed; if BASE is
+ 1, 1-based column numbers are parsed. Regardless of BASE, the
+ values stored in *FIRST_COLUMN and *LAST_COLUMN are
+ 1-based. */
+bool
+parse_column (struct lexer *lexer, int base, int *column)
+{
+ assert (base == 0 || base == 1);
+
+ if (!lex_force_int (lexer)
+ || !parse_column__ (lex_integer (lexer), base, column))
+ return false;
+
+ lex_get (lexer);
+ return true;
+}
+
/* Parse a column or a range of columns, specified as a single
integer or two integers delimited by a dash. Stores the range
in *FIRST_COLUMN and *LAST_COLUMN. (If only a single integer
{
/* First column. */
if (!lex_force_int (lexer)
- || !parse_column (lex_integer (lexer), base, first_column))
+ || !parse_column__ (lex_integer (lexer), base, first_column))
return false;
lex_get (lexer);
/* Last column. */
if (lex_is_integer (lexer) && lex_integer (lexer) < 0)
{
- if (!parse_column (-lex_integer (lexer), base, last_column))
+ if (!parse_column__ (-lex_integer (lexer), base, last_column))
return false;
lex_get (lexer);
struct fmt_spec **, size_t *format_cnt);
bool execute_placement_format (const struct fmt_spec *,
int *record, int *column);
+bool parse_column (struct lexer *lexer, int base, int *column);
bool parse_column_range (struct lexer *, int base,
int *first_column, int *last_column,
bool *range_specified);
#include <config.h>
#include <stdlib.h>
+#include <uniwidth.h>
#include "data/case.h"
#include "data/dataset.h"
#include "libpspp/message.h"
#include "libpspp/misc.h"
#include "libpspp/pool.h"
+#include "libpspp/u8-line.h"
#include "output/tab.h"
#include "output/text-item.h"
/* PRT_LITERAL only. */
struct string string; /* String to output. */
+ int width; /* Width of 'string', in display columns. */
};
static inline struct prt_out_spec *
struct dfm_writer *writer; /* Output file, NULL=listing file. */
struct ll_list specs; /* List of struct prt_out_specs. */
size_t record_cnt; /* Number of records to write. */
- struct string line; /* Output buffer. */
};
enum which_formats
static int internal_cmd_print (struct lexer *, struct dataset *ds,
enum which_formats, bool eject);
-static trns_proc_func print_trns_proc;
+static trns_proc_func print_text_trns_proc, print_binary_trns_proc;
static trns_free_func print_trns_free;
static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *,
struct dictionary *dict, enum which_formats);
internal_cmd_print (struct lexer *lexer, struct dataset *ds,
enum which_formats which_formats, bool eject)
{
- bool print_table = 0;
+ bool print_table = false;
+ const struct prt_out_spec *spec;
struct print_trns *trns;
struct file_handle *fh = NULL;
char *encoding = NULL;
struct pool *tmp_pool;
+ bool binary;
/* Fill in prt to facilitate error-handling. */
trns = pool_create_container (struct print_trns, pool);
trns->writer = NULL;
trns->record_cnt = 0;
ll_init (&trns->specs);
- ds_init_empty (&trns->line);
- ds_register_pool (&trns->line, trns->pool);
tmp_pool = pool_create_subpool (trns->pool);
if (!parse_specs (lexer, tmp_pool, trns, dataset_dict (ds), which_formats))
goto error;
+ /* Are there any binary formats?
+
+ There are real difficulties figuring out what to do when both binary
+ formats and nontrivial encodings enter the picture. So when binary
+ formats are present we fall back to much simpler handling. */
+ binary = false;
+ ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
+ {
+ if (spec->type == PRT_VAR
+ && fmt_get_category (spec->format.type) == FMT_CAT_BINARY)
+ {
+ binary = true;
+ break;
+ }
+ }
+ if (binary && fh == NULL)
+ {
+ msg (SE, _("OUTFILE is required when binary formats are specified."));
+ goto error;
+ }
+
if (lex_end_of_command (lexer) != CMD_SUCCESS)
goto error;
dump_table (trns, fh);
/* Put the transformation in the queue. */
- add_transformation (ds, print_trns_proc, print_trns_free, trns);
+ add_transformation (ds,
+ (binary
+ ? print_binary_trns_proc
+ : print_text_trns_proc),
+ print_trns_free, trns);
pool_destroy (tmp_pool);
fh_unref (fh);
if (lex_is_string (lexer))
ok = parse_string_argument (lexer, trns, record, &column);
else
- ok = parse_variable_argument (lexer, dict, trns, tmp_pool, &record, &column,
- which_formats);
+ ok = parse_variable_argument (lexer, dict, trns, tmp_pool, &record,
+ &column, which_formats);
if (!ok)
return 0;
if (range_specified)
ds_set_length (&spec->string, last_column - first_column + 1, ' ');
}
- *column = spec->first_column + ds_length (&spec->string);
+
+ spec->width = u8_strwidth (CHAR_CAST (const uint8_t *,
+ ds_cstr (&spec->string)),
+ UTF8);
+ *column = spec->first_column + spec->width;
ll_push_tail (&trns->specs, &spec->ll);
return true;
tab_submit (t);
}
\f
-/* Transformation. */
+/* Transformation, for all-text output. */
-static void flush_records (struct print_trns *, int target_record,
- bool *eject, int *record);
+static void print_text_flush_records (struct print_trns *, struct u8_line *,
+ int target_record,
+ bool *eject, int *record);
/* Performs the transformation inside print_trns T on case C. */
static int
-print_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
+print_text_trns_proc (void *trns_, struct ccase **c,
+ casenumber case_num UNUSED)
{
struct print_trns *trns = trns_;
+ struct prt_out_spec *spec;
+ struct u8_line line;
+
bool eject = trns->eject;
- char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
int record = 1;
- struct prt_out_spec *spec;
- ds_clear (&trns->line);
- ds_put_byte (&trns->line, ' ');
+ u8_line_init (&line);
ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
{
- flush_records (trns, spec->record, &eject, &record);
+ int x0 = spec->first_column;
- ds_set_length (&trns->line, spec->first_column, encoded_space);
+ print_text_flush_records (trns, &line, spec->record, &eject, &record);
+
+ u8_line_set_length (&line, spec->first_column);
if (spec->type == PRT_VAR)
{
const union value *input = case_data (*c, spec->var);
+ int x1;
+
if (!spec->sysmis_as_spaces || input->f != SYSMIS)
- data_out_recode (input, var_get_encoding (spec->var),
- &spec->format, &trns->line, trns->encoding);
+ {
+ size_t len;
+ int width;
+ char *s;
+
+ s = data_out (input, var_get_encoding (spec->var),
+ &spec->format);
+ len = strlen (s);
+ width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
+ x1 = x0 + width;
+ u8_line_put (&line, x0, x1, s, len);
+ free (s);
+ }
else
- ds_put_byte_multiple (&trns->line, encoded_space, spec->format.w);
+ {
+ int n = spec->format.w;
+
+ x1 = x0 + n;
+ memset (u8_line_reserve (&line, x0, x1, n), ' ', n);
+ }
+
if (spec->add_space)
- ds_put_byte (&trns->line, encoded_space);
+ *u8_line_reserve (&line, x1, x1 + 1, 1) = ' ';
}
else
{
- ds_put_substring (&trns->line, ds_ss (&spec->string));
- if (0 != strcmp (trns->encoding, C_ENCODING))
- {
- size_t length = ds_length (&spec->string);
- char *data = ss_data (ds_tail (&trns->line, length));
- char *s = recode_string (trns->encoding, C_ENCODING, data, length);
- memcpy (data, s, length);
- free (s);
- }
+ const struct string *s = &spec->string;
+
+ u8_line_put (&line, x0, x0 + spec->width,
+ ds_data (s), ds_length (s));
}
}
- flush_records (trns, trns->record_cnt + 1, &eject, &record);
+ print_text_flush_records (trns, &line, trns->record_cnt + 1,
+ &eject, &record);
+ u8_line_destroy (&line);
if (trns->writer != NULL && dfm_write_error (trns->writer))
return TRNS_ERROR;
output is preceded by ejecting the page (and *EJECT is set
false). */
static void
-flush_records (struct print_trns *trns, int target_record,
- bool *eject, int *record)
+print_text_flush_records (struct print_trns *trns, struct u8_line *line,
+ int target_record, bool *eject, int *record)
{
for (; target_record > *record; (*record)++)
{
- char *line = ds_cstr (&trns->line);
- size_t length = ds_length (&trns->line);
char leader = ' ';
if (*eject)
else
leader = '1';
}
- line[0] = recode_byte (trns->encoding, C_ENCODING, leader);
+ *u8_line_reserve (line, 0, 1, 1) = leader;
if (trns->writer == NULL)
- tab_output_text (TAB_FIX, &line[1]);
+ tab_output_text (TAB_FIX, ds_cstr (&line->s) + 1);
else
{
+ size_t len = ds_length (&line->s);
+ char *s = ds_cstr (&line->s);
+
if (!trns->include_prefix)
{
- line++;
- length--;
+ s++;
+ len--;
+ }
+
+ if (is_encoding_utf8 (trns->encoding))
+ dfm_put_record (trns->writer, s, len);
+ else
+ {
+ char *recoded = recode_string (trns->encoding, UTF8, s, len);
+ dfm_put_record (trns->writer, recoded, strlen (recoded));
+ free (recoded);
}
- dfm_put_record (trns->writer, line, length);
}
+ }
+}
+\f
+/* Transformation, for output involving binary. */
+
+static void print_binary_flush_records (struct print_trns *,
+ struct string *line, int target_record,
+ bool *eject, int *record);
+
+/* Performs the transformation inside print_trns T on case C. */
+static int
+print_binary_trns_proc (void *trns_, struct ccase **c,
+ casenumber case_num UNUSED)
+{
+ struct print_trns *trns = trns_;
+ bool eject = trns->eject;
+ char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
+ int record = 1;
+ struct prt_out_spec *spec;
+ struct string line;
+
+ ds_init_empty (&line);
+ ds_put_byte (&line, ' ');
+ ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
+ {
+ print_binary_flush_records (trns, &line, spec->record, &eject, &record);
- ds_truncate (&trns->line, 1);
+ ds_set_length (&line, spec->first_column, encoded_space);
+ if (spec->type == PRT_VAR)
+ {
+ const union value *input = case_data (*c, spec->var);
+ if (!spec->sysmis_as_spaces || input->f != SYSMIS)
+ data_out_recode (input, var_get_encoding (spec->var),
+ &spec->format, &line, trns->encoding);
+ else
+ ds_put_byte_multiple (&line, encoded_space, spec->format.w);
+ if (spec->add_space)
+ ds_put_byte (&line, encoded_space);
+ }
+ else
+ {
+ ds_put_substring (&line, ds_ss (&spec->string));
+ if (0 != strcmp (trns->encoding, UTF8))
+ {
+ size_t length = ds_length (&spec->string);
+ char *data = ss_data (ds_tail (&line, length));
+ char *s = recode_string (trns->encoding, UTF8, data, length);
+ memcpy (data, s, length);
+ free (s);
+ }
+ }
}
+ print_binary_flush_records (trns, &line, trns->record_cnt + 1,
+ &eject, &record);
+ ds_destroy (&line);
+
+ if (trns->writer != NULL && dfm_write_error (trns->writer))
+ return TRNS_ERROR;
+ return TRNS_CONTINUE;
}
+/* Advance from *RECORD to TARGET_RECORD, outputting records
+ along the way. If *EJECT is true, then the first record
+ output is preceded by ejecting the page (and *EJECT is set
+ false). */
+static void
+print_binary_flush_records (struct print_trns *trns, struct string *line,
+ int target_record, bool *eject, int *record)
+{
+ for (; target_record > *record; (*record)++)
+ {
+ char *s = ds_cstr (line);
+ size_t length = ds_length (line);
+ char leader = ' ';
+
+ if (*eject)
+ {
+ *eject = false;
+ leader = '1';
+ }
+ s[0] = recode_byte (trns->encoding, C_ENCODING, leader);
+
+ if (!trns->include_prefix)
+ {
+ s++;
+ length--;
+ }
+ dfm_put_record (trns->writer, s, length);
+
+ ds_truncate (line, 1);
+ }
+}
+\f
/* Frees TRNS. */
static bool
print_trns_free (void *trns_)
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/assertion.h"
#include "libpspp/bit-vector.h"
#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
#include "libpspp/message.h"
#include "libpspp/misc.h"
#include "libpspp/str.h"
result = a_index < b_index ? -1 : a_index > b_index;
}
else
- result = strcasecmp (var_get_name (a), var_get_name (b));
+ result = utf8_strcasecmp (var_get_name (a), var_get_name (b));
if (!ordering->forward)
result = -result;
return result;
const struct var_renaming *a = a_;
const struct var_renaming *b = b_;
- return strcasecmp (a->new_name, b->new_name);
+ return utf8_strcasecmp (a->new_name, b->new_name);
}
/* Returns true if performing VM on dictionary D would not cause
/* PSPP - a program for statistical analysis.
- Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
if (width == c->width
&& value_equal (value, &c->value, width))
{
- if (!c->warned && strcasecmp (c->label, label))
+ if (!c->warned && utf8_strcasecmp (c->label, label))
{
char *s = data_out (value, var_get_encoding (var),
var_get_print_format (var));
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "language/lexer/lexer.h"
#include "language/lexer/variable-parser.h"
#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
#include "libpspp/message.h"
#include "libpspp/misc.h"
#include "libpspp/pool.h"
}
for (i = 0; i < vector_cnt; i++)
- if (!strcasecmp (vectors[i], lex_tokcstr (lexer)))
+ if (!utf8_strcasecmp (vectors[i], lex_tokcstr (lexer)))
{
msg (SE, _("Vector name %s is given twice."),
lex_tokcstr (lexer));
#include "libpspp/pool.h"
#include "libpspp/str.h"
+#include "gl/c-strcase.h"
#include "gl/xalloc.h"
\f
/* Declarations. */
static int
compare_strings (const char *test, const char *name, bool abbrev_ok UNUSED)
{
- return strcasecmp (test, name);
+ return c_strcasecmp (test, name);
}
static bool
#include "libpspp/cast.h"
#include "gl/c-ctype.h"
+#include "gl/c-strtod.h"
#include "gl/xmemdup0.h"
enum
else
p = xmemdup0 (s.string, s.length);
- number = strtod (p, NULL);
+ number = c_strtod (p, NULL);
if (p != buf)
free (p);
#include "data/identifier.h"
#include "libpspp/assertion.h"
#include "libpspp/cast.h"
+#include "libpspp/misc.h"
+
#include "gl/ftoastr.h"
#include "gl/xalloc.h"
{
char buffer[DBL_BUFSIZE_BOUND];
- dtoastr (buffer, sizeof buffer, 0, 0, fabs (token->number));
+ c_dtoastr (buffer, sizeof buffer, 0, 0, fabs (token->number));
return (token->type == T_POS_NUM
? xstrdup (buffer)
: xasprintf ("-%s", buffer));
{
char s[DBL_BUFSIZE_BOUND];
- dtoastr (s, sizeof s, 0, 0, token->number);
+ c_dtoastr (s, sizeof s, 0, 0, token->number);
fprintf (stream, "\t%s", s);
}
if (token->type == T_ID || token->type == T_STRING || token->string.length)
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/assertion.h"
#include "libpspp/cast.h"
#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
#include "libpspp/hmapx.h"
#include "libpspp/message.h"
#include "libpspp/misc.h"
struct hmapx_node *node;
struct variable **varp;
- HMAPX_FOR_EACH_WITH_HASH (varp, node, hash_case_string (name, 0),
+ HMAPX_FOR_EACH_WITH_HASH (varp, node, utf8_hash_case_string (name, 0),
&avs->vars_by_name)
- if (!strcasecmp (name, var_get_name (*varp)))
+ if (!utf8_strcasecmp (name, var_get_name (*varp)))
{
*idx = varp - avs->var;
return true;
return NULL;
}
hmapx_insert (&avs->vars_by_name, CONST_CAST (void *, &avs->var[i]),
- hash_case_string (name, 0));
+ utf8_hash_case_string (name, 0));
}
return vs;
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "math/sort.h"
#include "math/statistic.h"
+#include "gl/c-strcase.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
exclude = ds_chomp_byte (&function_name, '.') ? MV_SYSTEM : MV_ANY;
for (function = agr_func_tab; function->name; function++)
- if (!strcasecmp (function->name, ds_cstr (&function_name)))
+ if (!c_strcasecmp (function->name, ds_cstr (&function_name)))
break;
if (NULL == function->name)
{
#include "libpspp/str.h"
#include "gl/xalloc.h"
-#include "gl/vasnprintf.h"
+#include "gl/c-xvasprintf.h"
#include "gl/mbiter.h"
+
#include "gettext.h"
#define _(msgid) gettext (msgid)
for (j = 0; j < n_items; j++)
{
const union value *from = &items[j]->from;
- size_t len;
char *recoded_value = NULL;
char *c;
const int src_width = items[j]->width;
recoded_value = recode_string (UTF8, dict_get_encoding (arc->dict), str, src_width);
}
else
- recoded_value = asnprintf (NULL, &len, "%g", from->f);
+ recoded_value = c_xasprintf ("%g", from->f);
/* Remove trailing whitespace */
for (c = recoded_value; *c != '\0'; c++)
for (i = 0; i < dsc->var_cnt; i++)
{
struct dsc_var *dsc_var = &dsc->vars[i];
- if (dsc_var->z_name != NULL && !strcasecmp (dsc_var->z_name, name))
+ if (dsc_var->z_name != NULL && !utf8_strcasecmp (dsc_var->z_name, name))
return false;
}
return true;
int result;
if (dsc->sort_by_stat == DSC_NAME)
- result = strcasecmp (var_get_name (a->v), var_get_name (b->v));
+ result = utf8_strcasecmp (var_get_name (a->v), var_get_name (b->v));
else
{
double as = a->stats[dsc->sort_by_stat];
{
cstp->ranged = true;
if ( ! lex_force_num (lexer)) return 0;
- cstp->lo = lex_integer (lexer);
+ cstp->lo = lex_number (lexer);
lex_get (lexer);
lex_force_match (lexer, T_COMMA);
if (! lex_force_num (lexer) ) return 0;
- cstp->hi = lex_integer (lexer);
+ cstp->hi = lex_number (lexer);
if ( cstp->lo >= cstp->hi )
{
msg (ME,
src/libpspp/tower.h \
src/libpspp/u8-istream.c \
src/libpspp/u8-istream.h \
+ src/libpspp/u8-line.c \
+ src/libpspp/u8-line.h \
src/libpspp/version.h \
src/libpspp/zip-private.h \
src/libpspp/zip-reader.c \
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
return hash_bytes (s, strlen (s), basis);
}
-/* Returns a hash value for the N bytes at S, with lowercase and uppercase
- letters treated as equal, starting from BASIS. */
-unsigned int
-hash_case_bytes (const void *s_, size_t n, unsigned int basis)
-{
- const char *s = s_;
- uint32_t a, b, c;
- uint32_t tmp[3];
- int i;
-
- a = b = c = 0xdeadbeef + n + basis;
-
- while (n >= 12)
- {
- for (i = 0; i < 12; i++)
- ((unsigned char *)tmp)[i] = toupper ((unsigned char) s[i]);
- a += tmp[0];
- b += tmp[1];
- c += tmp[2];
- HASH_MIX (a, b, c);
- n -= 12;
- s += 12;
- }
-
- if (n > 0)
- {
- memset (tmp, 0, 12);
- for (i = 0; i < n; i++)
- ((unsigned char *)tmp)[i] = toupper ((unsigned char) s[i]);
- a += tmp[0];
- b += tmp[1];
- c += tmp[2];
- }
-
- HASH_FINAL (a, b, c);
- return c;
-}
-
-/* Returns a hash value for null-terminated string S, with
- lowercase and uppercase letters treated as equal, starting
- from BASIS. */
-unsigned int
-hash_case_string (const char *s, unsigned int basis)
-{
- return hash_case_bytes (s, strlen (s), basis);
-}
-
/* Returns a hash value for integer X, starting from BASIS. */
unsigned int
hash_int (int x, unsigned int basis)
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009, 2010, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
unsigned int hash_bytes (const void *, size_t, unsigned int basis);
unsigned int hash_string (const char *, unsigned int basis);
-unsigned int hash_case_bytes (const void *, size_t, unsigned int basis);
-unsigned int hash_case_string (const char *, unsigned int basis);
unsigned int hash_int (int, unsigned int basis);
unsigned int hash_double (double, unsigned int basis);
unsigned int hash_pointer (const void *, unsigned int basis);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unicase.h>
#include <unigbrk.h>
#include "libpspp/assertion.h"
#include "gl/c-strcase.h"
#include "gl/localcharset.h"
+#include "gl/minmax.h"
#include "gl/xalloc.h"
#include "gl/relocatable.h"
#include "gl/xstrndup.h"
void
i18n_init (void)
{
- setlocale (LC_CTYPE, "");
- setlocale (LC_COLLATE, "");
- setlocale (LC_MESSAGES, "");
-#if HAVE_LC_PAPER
- setlocale (LC_PAPER, "");
-#endif
+ setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, relocate(locale_dir));
textdomain (PACKAGE);
ok = false;
}
-
setlocale (LC_CTYPE, tmp);
free (tmp);
{
char radix_char;
- char *ol = xstrdup (setlocale (LC_NUMERIC, NULL));
- setlocale (LC_NUMERIC, "");
-
#if HAVE_NL_LANGINFO
radix_char = nl_langinfo (RADIXCHAR)[0];
#else
}
#endif
- /* We MUST leave LC_NUMERIC untouched, since it would
- otherwise interfere with data_{in,out} */
- setlocale (LC_NUMERIC, ol);
- free (ol);
return radix_char;
}
return buffer;
}
\f
+/* UTF-8 functions that deal with uppercase/lowercase distinctions. */
+
+/* Returns a hash value for the N bytes of UTF-8 encoded data starting at S,
+ with lowercase and uppercase letters treated as equal, starting from
+ BASIS. */
+unsigned int
+utf8_hash_case_bytes (const char *s, size_t n, unsigned int basis)
+{
+ uint8_t folded_buf[2048];
+ size_t folded_len = sizeof folded_buf;
+ uint8_t *folded_s;
+ unsigned int hash;
+
+ folded_s = u8_casefold (CHAR_CAST (const uint8_t *, s), n,
+ NULL, UNINORM_NFKD, folded_buf, &folded_len);
+ if (folded_s != NULL)
+ {
+ hash = hash_bytes (folded_s, folded_len, basis);
+ if (folded_s != folded_buf)
+ free (folded_s);
+ }
+ else
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+ hash = hash_bytes (s, n, basis);
+ }
+
+ return hash;
+}
+
+/* Returns a hash value for null-terminated UTF-8 string S, with lowercase and
+ uppercase letters treated as equal, starting from BASIS. */
+unsigned int
+utf8_hash_case_string (const char *s, unsigned int basis)
+{
+ return utf8_hash_case_bytes (s, strlen (s), basis);
+}
+
+/* Compares UTF-8 strings A and B case-insensitively.
+ Returns a negative value if A < B, zero if A == B, positive if A > B. */
+int
+utf8_strcasecmp (const char *a, const char *b)
+{
+ return utf8_strncasecmp (a, strlen (a), b, strlen (b));
+}
+
+/* Compares UTF-8 strings A (with length AN) and B (with length BN)
+ case-insensitively.
+ Returns a negative value if A < B, zero if A == B, positive if A > B. */
+int
+utf8_strncasecmp (const char *a, size_t an, const char *b, size_t bn)
+{
+ int result;
+
+ if (u8_casecmp (CHAR_CAST (const uint8_t *, a), an,
+ CHAR_CAST (const uint8_t *, b), bn,
+ NULL, UNINORM_NFKD, &result))
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+
+ result = memcmp (a, b, MIN (an, bn));
+ if (result == 0)
+ result = an < bn ? -1 : an > bn;
+ }
+
+ return result;
+}
+
+static char *
+utf8_casemap (const char *s,
+ uint8_t *(*f) (const uint8_t *, size_t, const char *, uninorm_t,
+ uint8_t *, size_t *))
+{
+ char *result;
+ size_t size;
+
+ result = CHAR_CAST (char *,
+ f (CHAR_CAST (const uint8_t *, s), strlen (s) + 1,
+ NULL, NULL, NULL, &size));
+ if (result == NULL)
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+
+ result = xstrdup (s);
+ }
+ return result;
+}
+
+char *
+utf8_to_upper (const char *s)
+{
+ return utf8_casemap (s, u8_toupper);
+}
+
+char *
+utf8_to_lower (const char *s)
+{
+ return utf8_casemap (s, u8_tolower);
+}
+\f
bool
get_encoding_info (struct encoding_info *e, const char *name)
{
bool set_encoding_from_locale (const char *loc);
const char *uc_name (ucs4_t uc, char buffer[16]);
+
+unsigned int utf8_hash_case_bytes (const char *, size_t n, unsigned int basis);
+unsigned int utf8_hash_case_string (const char *, unsigned int basis);
+int utf8_strcasecmp (const char *, const char *);
+int utf8_strncasecmp (const char *, size_t, const char *, size_t);
+char *utf8_to_upper (const char *);
+char *utf8_to_lower (const char *);
\f
/* Information about character encodings. */
#include <config.h>
#include "misc.h"
+#include <gl/ftoastr.h>
/* Returns the number of digits in X. */
int
return digits;
}
+
+/* A locale independent version of dtoastr (from gnulib) */
+int
+c_dtoastr (char *buf, size_t bufsize, int flags, int width, double x)
+{
+ int i;
+ int result = dtoastr (buf, bufsize, flags, width, x);
+
+ /* Replace the first , (if any) by a . */
+ for (i = 0; i < result; ++i)
+ {
+ if (buf[i] == ',')
+ {
+ buf[i] = '.';
+ break;
+ }
+ }
+
+ return result;
+}
#if !libpspp_misc_h
#define libpspp_misc_h 1
+#include <stddef.h>
#include <float.h>
#include <math.h>
*dest = src;
}
+int c_dtoastr (char *buf, size_t bufsize, int flags, int width, double x);
+
#endif /* libpspp/misc.h */
#include "libpspp/message.h"
#include "libpspp/pool.h"
+#include "gl/c-ctype.h"
+#include "gl/c-vasnprintf.h"
#include "gl/relocatable.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
dst[dst_len] = '\0';
}
-/* Converts each byte in S to uppercase. */
+/* Converts each byte in S to uppercase.
+
+ This is suitable only for ASCII strings. Use utf8_to_upper() for UTF-8
+ strings.*/
void
str_uppercase (char *s)
{
for (; *s != '\0'; s++)
- *s = toupper ((unsigned char) *s);
+ *s = c_toupper ((unsigned char) *s);
}
-/* Converts each byte in S to lowercase. */
+/* Converts each byte in S to lowercase.
+
+ This is suitable only for ASCII strings. Use utf8_to_lower() for UTF-8
+ strings.*/
void
str_lowercase (char *s)
{
for (; *s != '\0'; s++)
- *s = tolower ((unsigned char) *s);
+ *s = c_tolower ((unsigned char) *s);
}
/* Converts NUMBER into a string in 26-adic notation in BUFFER,
va_end (args);
}
-/* Formats FORMAT as a printf string and appends the result to ST. */
+/* Formats FORMAT as a printf string as if in the C locale and appends the result to ST. */
void
-ds_put_vformat (struct string *st, const char *format, va_list args_)
+ds_put_c_format (struct string *st, const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ ds_put_c_vformat (st, format, args);
+ va_end (args);
+}
+
+
+/* Formats FORMAT as a printf string, using fmt_func (a snprintf like function)
+ and appends the result to ST. */
+static void
+ds_put_vformat_int (struct string *st, const char *format, va_list args_,
+ int (*fmt_func) (char *, size_t, const char *, va_list))
{
int avail, needed;
va_list args;
va_copy (args, args_);
avail = st->ss.string != NULL ? st->capacity - st->ss.length + 1 : 0;
- needed = vsnprintf (st->ss.string + st->ss.length, avail, format, args);
+ needed = fmt_func (st->ss.string + st->ss.length, avail, format, args);
va_end (args);
if (needed >= avail)
{
va_copy (args, args_);
- vsprintf (ds_put_uninit (st, needed), format, args);
+ fmt_func (ds_put_uninit (st, needed), needed + 1, format, args);
va_end (args);
}
else
avail = st->capacity - st->ss.length + 1;
va_copy (args, args_);
- needed = vsnprintf (ds_end (st), avail, format, args);
+ needed = fmt_func (ds_end (st), avail, format, args);
va_end (args);
}
st->ss.length += needed;
}
}
+
+static int
+vasnwrapper (char *str, size_t size, const char *format, va_list ap)
+{
+ c_vasnprintf (str, &size, format, ap);
+ return size;
+}
+
+/* Formats FORMAT as a printf string and appends the result to ST. */
+void
+ds_put_vformat (struct string *st, const char *format, va_list args_)
+{
+ ds_put_vformat_int (st, format, args_, vsnprintf);
+}
+
+/* Formats FORMAT as a printf string, as if in the C locale,
+ and appends the result to ST. */
+void
+ds_put_c_vformat (struct string *st, const char *format, va_list args_)
+{
+ ds_put_vformat_int (st, format, args_, vasnwrapper);
+}
+
/* Appends byte CH to ST. */
void
ds_put_byte (struct string *st, int ch)
void ds_put_substring (struct string *, struct substring);
void ds_put_vformat (struct string *st, const char *, va_list)
PRINTF_FORMAT (2, 0);
+void ds_put_c_vformat (struct string *st, const char *, va_list)
+ PRINTF_FORMAT (2, 0);
+
void ds_put_format (struct string *, const char *, ...)
PRINTF_FORMAT (2, 3);
+void ds_put_c_format (struct string *, const char *, ...)
+ PRINTF_FORMAT (2, 3);
+
char *ds_put_uninit (struct string *st, size_t incr);
char *ds_splice_uninit (struct string *, size_t ofs, size_t old_len,
/* PSPP - a program for statistical analysis.
- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <string.h>
#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
#include "libpspp/string-set.h"
#include "libpspp/stringi-set.h"
struct stringi_map_node *
stringi_map_find_node (const struct stringi_map *map, const char *key)
{
- return stringi_map_find_node__ (map, key, hash_case_string (key, 0));
+ return stringi_map_find_node__ (map, key, utf8_hash_case_string (key, 0));
}
/* If MAP contains KEY (or an equivalent with different case) as a key, deletes
stringi_map_insert (struct stringi_map *map, const char *key,
const char *value)
{
- unsigned int hash = hash_case_string (key, 0);
+ unsigned int hash = utf8_hash_case_string (key, 0);
struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
if (node == NULL)
node = stringi_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
struct stringi_map_node *
stringi_map_insert_nocopy (struct stringi_map *map, char *key, char *value)
{
- unsigned int hash = hash_case_string (key, 0);
+ unsigned int hash = utf8_hash_case_string (key, 0);
struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
if (node == NULL)
node = stringi_map_insert__ (map, key, value, hash);
stringi_map_replace (struct stringi_map *map, const char *key,
const char *value)
{
- unsigned int hash = hash_case_string (key, 0);
+ unsigned int hash = utf8_hash_case_string (key, 0);
struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
if (node == NULL)
node = stringi_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
struct stringi_map_node *
stringi_map_replace_nocopy (struct stringi_map *map, char *key, char *value)
{
- unsigned int hash = hash_case_string (key, 0);
+ unsigned int hash = utf8_hash_case_string (key, 0);
struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
if (node == NULL)
node = stringi_map_insert__ (map, key, value, hash);
bool
stringi_map_delete (struct stringi_map *map, const char *key)
{
- return stringi_map_delete__ (map, key, hash_case_string (key, 0));
+ return stringi_map_delete__ (map, key, utf8_hash_case_string (key, 0));
}
/* Deletes NODE from MAP and destroys the node and its key and value. */
HMAP_FOR_EACH_WITH_HASH (node, struct stringi_map_node, hmap_node,
hash, &map->hmap)
- if (!strcasecmp (key, node->key))
+ if (!utf8_strcasecmp (key, node->key))
return node;
return NULL;
/* PSPP - a program for statistical analysis.
- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/cast.h"
#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
#include "gl/xalloc.h"
struct stringi_set_node *
stringi_set_find_node (const struct stringi_set *set, const char *s)
{
- return stringi_set_find_node__ (set, s, hash_case_string (s, 0));
+ return stringi_set_find_node__ (set, s, utf8_hash_case_string (s, 0));
}
/* Inserts a copy of S into SET. Returns true if successful, false if SET
bool
stringi_set_insert (struct stringi_set *set, const char *s)
{
- unsigned int hash = hash_case_string (s, 0);
+ unsigned int hash = utf8_hash_case_string (s, 0);
if (!stringi_set_find_node__ (set, s, hash))
{
stringi_set_insert__ (set, xstrdup (s), hash);
bool
stringi_set_insert_nocopy (struct stringi_set *set, char *s)
{
- unsigned int hash = hash_case_string (s, 0);
+ unsigned int hash = utf8_hash_case_string (s, 0);
if (!stringi_set_find_node__ (set, s, hash))
{
stringi_set_insert__ (set, s, hash);
bool
stringi_set_delete (struct stringi_set *set, const char *s)
{
- return stringi_set_delete__ (set, s, hash_case_string (s, 0));
+ return stringi_set_delete__ (set, s, utf8_hash_case_string (s, 0));
}
/* Deletes NODE from SET, and frees NODE and its string. */
{
const char *const *a = a_;
const char *const *b = b_;
- return strcasecmp (*a, *b);
+ return utf8_strcasecmp (*a, *b);
}
/* Allocates and returns an array that points to each of the strings in SET.
caller it is responsible for freeing the returned array itself (with
free()).
- The returned array is ordered according to strcasecmp(). */
+ The returned array is ordered according to utf8_strcasecmp(). */
char **
stringi_set_get_sorted_array (const struct stringi_set *set)
{
HMAP_FOR_EACH_WITH_HASH (node, struct stringi_set_node, hmap_node,
hash, &set->hmap)
- if (!strcasecmp (s, node->string))
+ if (!utf8_strcasecmp (s, node->string))
return node;
return NULL;
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "libpspp/u8-line.h"
+#include <unistr.h>
+#include <uniwidth.h>
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+
+/* Initializes LINE as an empty u8_line. */
+void
+u8_line_init (struct u8_line *line)
+{
+ ds_init_empty (&line->s);
+ line->width = 0;
+}
+
+/* Frees data owned by LINE. */
+void
+u8_line_destroy (struct u8_line *line)
+{
+ ds_destroy (&line->s);
+}
+
+/* Clears LINE to zero length. */
+void
+u8_line_clear (struct u8_line *line)
+{
+ ds_clear (&line->s);
+ line->width = 0;
+}
+
+static int
+u8_mb_to_display (int *wp, const uint8_t *s, size_t n)
+{
+ size_t ofs;
+ ucs4_t uc;
+ int w;
+
+ ofs = u8_mbtouc (&uc, s, n);
+ if (ofs < n && s[ofs] == '\b')
+ {
+ ofs++;
+ ofs += u8_mbtouc (&uc, s + ofs, n - ofs);
+ }
+
+ w = uc_width (uc, "UTF-8");
+ if (w <= 0)
+ {
+ *wp = 0;
+ return ofs;
+ }
+
+ while (ofs < n)
+ {
+ int mblen = u8_mbtouc (&uc, s + ofs, n - ofs);
+ if (uc_width (uc, "UTF-8") > 0)
+ break;
+ ofs += mblen;
+ }
+
+ *wp = w;
+ return ofs;
+}
+
+/* Position of a character within a u8_line. */
+struct u8_pos
+ {
+ /* 0-based display columns.
+
+ For a single-width character, x1 == x0 + 1.
+ For a double-width character, x1 == x0 + 2. */
+ int x0;
+ int x1;
+
+ /* Byte offsets.
+
+ For an ordinary ASCII character, ofs1 == ofs0 + 1.
+ For Unicode code point 0x80 or higher, 2 <= ofs1 - ofs0 <= 4. */
+ size_t ofs0;
+ size_t ofs1;
+ };
+
+static void
+u8_line_find_pos (struct u8_line *line, int target_x, struct u8_pos *c)
+{
+ const uint8_t *s = CHAR_CAST (const uint8_t *, ds_cstr (&line->s));
+ size_t length = ds_length (&line->s);
+ size_t ofs;
+ int mblen;
+ int x;
+
+ x = 0;
+ for (ofs = 0; ; ofs += mblen)
+ {
+ int w;
+
+ mblen = u8_mb_to_display (&w, s + ofs, length - ofs);
+ if (x + w > target_x)
+ {
+ c->x0 = x;
+ c->x1 = x + w;
+ c->ofs0 = ofs;
+ c->ofs1 = ofs + mblen;
+ return;
+ }
+ x += w;
+ }
+}
+
+/* Prepares LINE to write N bytes of characters that comprise X1-X0 column
+ widths starting at 0-based column X0. Returns the first byte of the N for
+ the caller to fill in. */
+char *
+u8_line_reserve (struct u8_line *line, int x0, int x1, int n)
+{
+ if (x0 >= line->width)
+ {
+ /* The common case: adding new characters at the end of a line. */
+ ds_put_byte_multiple (&line->s, ' ', x0 - line->width);
+ line->width = x1;
+ return ds_put_uninit (&line->s, n);
+ }
+ else if (x0 == x1)
+ return NULL;
+ else
+ {
+ /* An unusual case: overwriting characters in the middle of a line. We
+ don't keep any kind of mapping from bytes to display positions, so we
+ have to iterate over the whole line starting from the beginning. */
+ struct u8_pos p0, p1;
+ char *s;
+
+ /* Find the positions of the first and last character. We must find both
+ characters' positions before changing the line, because that would
+ prevent finding the other character's position. */
+ u8_line_find_pos (line, x0, &p0);
+ if (x1 < line->width)
+ u8_line_find_pos (line, x1, &p1);
+
+ /* If a double-width character occupies both x0 - 1 and x0, then replace
+ its first character width by '?'. */
+ s = ds_data (&line->s);
+ while (p0.x0 < x0)
+ {
+ s[p0.ofs0++] = '?';
+ p0.x0++;
+ }
+
+ if (x1 >= line->width)
+ {
+ ds_truncate (&line->s, p0.ofs0);
+ line->width = x1;
+ return ds_put_uninit (&line->s, n);
+ }
+
+ /* If a double-width character occupies both x1 - 1 and x1, then replace
+ its second character width by '?'. */
+ if (p1.x0 < x1)
+ {
+ do
+ {
+ s[--p1.ofs1] = '?';
+ p1.x0++;
+ }
+ while (p1.x0 < x1);
+ return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs1 - p0.ofs0, n);
+ }
+
+ return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs0 - p0.ofs0, n);
+ }
+}
+
+/* Writes the N bytes of characters that comprise X1-X0 column widths into LINE
+ starting at 0-based column X0. */
+void
+u8_line_put (struct u8_line *line, int x0, int x1, const char *s, int n)
+{
+ memcpy (u8_line_reserve (line, x0, x1, n), s, n);
+}
+
+/* Changes the width of LINE to X column widths. If X is longer than LINE's
+ previous width, LINE is extended by appending spaces. If X is shorter than
+ LINE's previous width, LINE is shortened by removing trailing characters. */
+void
+u8_line_set_length (struct u8_line *line, int x)
+{
+ if (x > line->width)
+ {
+ ds_put_byte_multiple (&line->s, ' ', x - line->width);
+ line->width = x;
+ }
+ else if (x < line->width)
+ {
+ struct u8_pos pos;
+
+ u8_line_find_pos (line, x, &pos);
+ ds_truncate (&line->s, pos.ofs0);
+ line->width = pos.x0;
+ if (x > line->width)
+ {
+ ds_put_byte_multiple (&line->s, '?', x - line->width);
+ line->width = x;
+ }
+ }
+}
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LIBPSPP_U8_LINE_H
+#define LIBPSPP_U8_LINE_H 1
+
+#include "libpspp/str.h"
+
+struct pool;
+
+/* A line of text, encoded in UTF-8, with support functions that properly
+ handle double-width characters and backspaces.
+
+ Designed to make appending text fast, and access and modification of other
+ column positions possible. */
+struct u8_line
+ {
+ struct string s; /* Content, in UTF-8. */
+ size_t width; /* Display width, in character positions. */
+ };
+
+void u8_line_init (struct u8_line *);
+void u8_line_destroy (struct u8_line *);
+void u8_line_clear (struct u8_line *);
+char *u8_line_reserve (struct u8_line *, int x0, int x1, int n);
+void u8_line_put (struct u8_line *, int x0, int x1, const char *s, int n);
+void u8_line_set_length (struct u8_line *, int x);
+
+#endif /* libpspp/u8-line.h */
#include <stdint.h>
#include <stdlib.h>
#include <signal.h>
-#include <unistd.h>
#include <unilbrk.h>
+#include <unistd.h>
#include <unistr.h>
#include <uniwidth.h>
#include "libpspp/message.h"
#include "libpspp/start-date.h"
#include "libpspp/string-map.h"
+#include "libpspp/u8-line.h"
#include "libpspp/version.h"
#include "output/ascii.h"
#include "output/cairo.h"
return ((right * 3 + bottom) * 3 + left) * 3 + top;
}
-/* A line of text. */
-struct ascii_line
- {
- struct string s; /* Content, in UTF-8. */
- size_t width; /* Display width, in character positions. */
- };
-
/* How to emphasize text. */
enum emphasis_style
{
FILE *file; /* Output file. */
bool error; /* Output error? */
int page_number; /* Current page number. */
- struct ascii_line *lines; /* Page content. */
+ struct u8_line *lines; /* Page content. */
int allocated_lines; /* Number of lines allocated. */
int chart_cnt; /* Number of charts so far. */
int y;
int i;
a->lines = xnrealloc (a->lines, a->length, sizeof *a->lines);
for (i = a->allocated_lines; i < a->length; i++)
- {
- struct ascii_line *line = &a->lines[i];
- ds_init_empty (&line->s);
- line->width = 0;
- }
+ u8_line_init (&a->lines[i]);
a->allocated_lines = a->length;
}
}
free (a->file_name);
free (a->chart_file_name);
for (i = 0; i < a->allocated_lines; i++)
- ds_destroy (&a->lines[i].s);
+ u8_line_destroy (&a->lines[i]);
free (a->lines);
free (a);
}
ascii_layout_cell (a, cell, bb, clip, &w, &h);
}
-static int
-u8_mb_to_display (int *wp, const uint8_t *s, size_t n)
-{
- size_t ofs;
- ucs4_t uc;
- int w;
-
- ofs = u8_mbtouc (&uc, s, n);
- if (ofs < n && s[ofs] == '\b')
- {
- ofs++;
- ofs += u8_mbtouc (&uc, s + ofs, n - ofs);
- }
-
- w = uc_width (uc, "UTF-8");
- if (w <= 0)
- {
- *wp = 0;
- return ofs;
- }
-
- while (ofs < n)
- {
- int mblen = u8_mbtouc (&uc, s + ofs, n - ofs);
- if (uc_width (uc, "UTF-8") > 0)
- break;
- ofs += mblen;
- }
-
- *wp = w;
- return ofs;
-}
-
-struct ascii_pos
- {
- int x0;
- int x1;
- size_t ofs0;
- size_t ofs1;
- };
-
-static void
-find_ascii_pos (struct ascii_line *line, int target_x, struct ascii_pos *c)
-{
- const uint8_t *s = CHAR_CAST (const uint8_t *, ds_cstr (&line->s));
- size_t length = ds_length (&line->s);
- size_t ofs;
- int mblen;
- int x;
-
- x = 0;
- for (ofs = 0; ; ofs += mblen)
- {
- int w;
-
- mblen = u8_mb_to_display (&w, s + ofs, length - ofs);
- if (x + w > target_x)
- {
- c->x0 = x;
- c->x1 = x + w;
- c->ofs0 = ofs;
- c->ofs1 = ofs + mblen;
- return;
- }
- x += w;
- }
-}
-
static char *
ascii_reserve (struct ascii_driver *a, int y, int x0, int x1, int n)
{
- struct ascii_line *line;
assert (y < a->allocated_lines);
- line = &a->lines[y];
-
- if (x0 >= line->width)
- {
- /* The common case: adding new characters at the end of a line. */
- ds_put_byte_multiple (&line->s, ' ', x0 - line->width);
- line->width = x1;
- return ds_put_uninit (&line->s, n);
- }
- else if (x0 == x1)
- return NULL;
- else
- {
- /* An unusual case: overwriting characters in the middle of a line. We
- don't keep any kind of mapping from bytes to display positions, so we
- have to iterate over the whole line starting from the beginning. */
- struct ascii_pos p0, p1;
- char *s;
-
- /* Find the positions of the first and last character. We must find the
- both characters' positions before changing the line, because that
- would prevent finding the other character's position. */
- find_ascii_pos (line, x0, &p0);
- if (x1 < line->width)
- find_ascii_pos (line, x1, &p1);
-
- /* If a double-width character occupies both x0 - 1 and x0, then replace
- its first character width by '?'. */
- s = ds_data (&line->s);
- while (p0.x0 < x0)
- {
- s[p0.ofs0++] = '?';
- p0.x0++;
- }
-
- if (x1 >= line->width)
- {
- ds_truncate (&line->s, p0.ofs0);
- line->width = x1;
- return ds_put_uninit (&line->s, n);
- }
-
- /* If a double-width character occupies both x1 - 1 and x1, then we need
- to replace its second character width by '?'. */
- if (p1.x0 < x1)
- {
- do
- {
- s[--p1.ofs1] = '?';
- p1.x0++;
- }
- while (p1.x0 < x1);
- return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs1 - p0.ofs0, n);
- }
-
- return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs0 - p0.ofs0, n);
- }
+ return u8_line_reserve (&a->lines[y], x0, x1, n);
}
static void
a->y = 1;
}
+
+void
+ascii_test_set_length (struct output_driver *driver, int y, int length)
+{
+ struct ascii_driver *a = ascii_driver_cast (driver);
+
+ if (a->file == NULL && !ascii_open_page (a))
+ return;
+
+ if (y < 0 || y >= a->length)
+ return;
+ u8_line_set_length (&a->lines[y], length);
+}
\f
/* ascii_close_page () and support routines. */
reallocate_lines (a);
for (i = 0; i < a->length; i++)
- {
- struct ascii_line *line = &a->lines[i];
- ds_clear (&line->s);
- line->width = 0;
- }
+ u8_line_clear (&a->lines[i]);
return true;
}
any_blank = false;
for (y = 0; y < a->allocated_lines; y++)
{
- struct ascii_line *line = &a->lines[y];
+ struct u8_line *line = &a->lines[y];
if (a->squeeze_blank_lines && y > 0 && line->width == 0)
any_blank = true;
/* PSPP - a program for statistical analysis.
- Copyright (C) 2011 Free Software Foundation, Inc.
+ Copyright (C) 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
void ascii_test_write (struct output_driver *,
const char *s, int x, int y, unsigned int options);
+void ascii_test_set_length (struct output_driver *, int y, int length);
#endif /* ascii.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "data/file-name.h"
#include "libpspp/str.h"
+#include "gl/c-strcase.h"
#include "gl/error.h"
#include "gettext.h"
unit += strspn (unit, CC_SPACES);
for (p = units; p < units + sizeof units / sizeof *units; p++)
- if (!strcasecmp (unit, p->name))
+ if (!c_strcasecmp (unit, p->name))
return p->factor;
return 0.0;
}
#include "dialog-common.h"
+#include <gl/c-xvasprintf.h>
#include <language/stats/aggregate.h>
#include <ui/syntax-gen.h>
gtk_entry_set_text (GTK_ENTRY (agg->summary_var_label_entry), label);
gtk_entry_set_text (GTK_ENTRY (agg->summary_sv_entry), srcvar);
- text = g_strdup_printf ("%g", arg1);
+ text = c_xasprintf ("%g", arg1);
gtk_entry_set_text (GTK_ENTRY (agg->summary_arg1_entry), text);
g_free (text);
- text = g_strdup_printf ("%g", arg2);
+ text = c_xasprintf ("%g", arg2);
gtk_entry_set_text (GTK_ENTRY (agg->summary_arg2_entry), text);
g_free (text);
-
gtk_combo_box_set_active (GTK_COMBO_BOX (agg->function_combo), f_idx);
}
if ( has_src_vars != AGR_SV_NO)
{
- g_string_append (string, " (");
+ struct string dss;
+ ds_init_cstr (&dss, " (");
- g_string_append (string, srcvar);
+ ds_put_cstr (&dss, srcvar);
if ( arity > 0)
- g_string_append_printf (string, ", %g", arg1);
+ ds_put_c_format (&dss, ", %g", arg1);
if ( arity > 1)
- g_string_append_printf (string, ", %g", arg2);
+ ds_put_c_format (&dss, ", %g", arg2);
+
+ ds_put_cstr (&dss, ")");
+
+ g_string_append (string, ds_cstr (&dss));
- g_string_append (string, ")");
+ ds_destroy (&dss);
}
free (label);
generate_syntax (const struct chisquare_dialog *scd)
{
gchar *text;
- GString *string;
+ struct string dss;
+ ds_init_cstr (&dss, "NPAR TEST\n\t/CHISQUARE=");
- string = g_string_new ("NPAR TEST\n\t/CHISQUARE=");
-
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (scd->var_view), 0, string);
-
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (scd->var_view), 0, &dss);
if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->range_button)))
{
- g_string_append (string, "(");
+ ds_put_cstr (&dss, "(");
- g_string_append (string,
+ ds_put_cstr (&dss,
gtk_entry_get_text (GTK_ENTRY (scd->value_lower)));
- g_string_append (string, ", ");
+ ds_put_cstr (&dss, ", ");
- g_string_append (string,
+ ds_put_cstr (&dss,
gtk_entry_get_text (GTK_ENTRY (scd->value_upper)));
- g_string_append (string, ")");
+ ds_put_cstr (&dss, ")");
}
-
-
-
if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->values_button)))
{
GtkListStore *ls = scd->expected_list;
GtkTreeIter iter;
gboolean ok;
- g_string_append (string, "\n\t");
- g_string_append (string, "/EXPECTED = ");
+ ds_put_cstr (&dss, "\n\t");
+ ds_put_cstr (&dss, "/EXPECTED = ");
for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(ls),
gtk_tree_model_get (GTK_TREE_MODEL (ls), &iter, 0, &v, -1);
- g_string_append_printf (string, " %g", v);
+ ds_put_c_format (&dss, " %g", v);
}
-
-
-
}
- g_string_append (string, ".\n");
+ ds_put_cstr (&dss, ".\n");
- text = string->str;
+ text = ds_steal_cstr (&dss);
- g_string_free (string, FALSE);
+ ds_destroy (&dss);
return text;
}
const gchar *s = NULL;
gboolean ok;
GtkTreeIter iter;
- GString *str = g_string_sized_new (100);
+ struct string dds;
+
+ ds_init_empty (&dds);
- g_string_append (str, "\nCOUNT ");
+ ds_put_cstr (&dds, "\nCOUNT ");
- g_string_append (str, gtk_entry_get_text (GTK_ENTRY (cnt->target)));
+ ds_put_cstr (&dds, gtk_entry_get_text (GTK_ENTRY (cnt->target)));
- g_string_append (str, " =");
+ ds_put_cstr (&dds, " =");
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (cnt->variable_treeview), 0, str);
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (cnt->variable_treeview), 0, &dds);
- g_string_append (str, "(");
+ ds_put_cstr (&dds, "(");
for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cnt->value_list),
&iter);
ok;
ov = g_value_get_boxed (&a_value);
- g_string_append (str, " ");
- old_value_append_syntax (str, ov);
+ ds_put_cstr (&dds, " ");
+ old_value_append_syntax (&dds, ov);
}
- g_string_append (str, ").");
+ ds_put_cstr (&dds, ").");
s = gtk_entry_get_text (GTK_ENTRY (cnt->label));
if (0 != strcmp (s, ""))
{
- struct string ds;
- ds_init_empty (&ds);
- g_string_append (str, "\nVARIABLE LABELS ");
+ ds_put_cstr (&dds, "\nVARIABLE LABELS ");
- g_string_append (str, gtk_entry_get_text (GTK_ENTRY (cnt->target)));
+ ds_put_cstr (&dds, gtk_entry_get_text (GTK_ENTRY (cnt->target)));
- g_string_append (str, " ");
+ ds_put_cstr (&dds, " ");
- syntax_gen_string (&ds, ss_cstr (s));
+ syntax_gen_string (&dds, ss_cstr (s));
- g_string_append (str, ds_cstr (&ds));
-
- g_string_append (str, ".");
- ds_destroy (&ds);
+ ds_put_cstr (&dds, ".");
}
- g_string_append (str, "\nEXECUTE.\n");
+ ds_put_cstr (&dds, "\nEXECUTE.\n");
- text = str->str;
+ text = ds_steal_cstr (&dds);
- g_string_free (str, FALSE);
+ ds_destroy (&dds);
return text;
}
gint i;
gboolean descriptives = gtk_toggle_button_get_active (ow->descriptives);
gboolean homogeneity = gtk_toggle_button_get_active (ow->homogeneity);
+ struct string dss;
- GString *str = g_string_new ("ONEWAY /VARIABLES=");
+ ds_init_cstr (&dss, "ONEWAY /VARIABLES=");
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (ow->vars_treeview), 0, str);
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (ow->vars_treeview), 0, &dss);
- g_string_append (str, " BY ");
+ ds_put_cstr (&dss, " BY ");
- g_string_append (str, gtk_entry_get_text (GTK_ENTRY (ow->factor_entry)));
+ ds_put_cstr (&dss, gtk_entry_get_text (GTK_ENTRY (ow->factor_entry)));
if (descriptives || homogeneity )
{
- g_string_append (str, "\n\t/STATISTICS=");
+ ds_put_cstr (&dss, "\n\t/STATISTICS=");
if (descriptives)
- g_string_append (str, "DESCRIPTIVES ");
+ ds_put_cstr (&dss, "DESCRIPTIVES ");
if (homogeneity)
- g_string_append (str, "HOMOGENEITY ");
+ ds_put_cstr (&dss, "HOMOGENEITY ");
}
for (i = 0 ; i < ow->contrasts_array->len ; ++i )
GtkTreeIter iter;
gboolean ok;
- g_string_append (str, "\n\t/CONTRAST=");
+ ds_put_cstr (&dss, "\n\t/CONTRAST=");
for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(ls),
&iter);
gtk_tree_model_get (GTK_TREE_MODEL (ls), &iter, 0, &v, -1);
- g_string_append_printf (str, " %g", v);
+ ds_put_c_format (&dss, " %g", v);
}
}
- g_string_append (str, ".\n");
+ ds_put_cstr (&dss, ".\n");
- text = str->str;
- g_string_free (str, FALSE);
+ text = ds_steal_cstr (&dss);
+ ds_destroy (&dss);
return text;
}
gchar *text = NULL;
double prop;
- GString *string = g_string_new ("NPAR TEST\n\t/BINOMIAL");
+ struct string str;
+
+ ds_init_cstr (&str, "NPAR TEST\n\t/BINOMIAL");
if ( get_proportion (scd, &prop))
- g_string_append_printf (string, "(%g)", prop);
+ ds_put_c_format (&str, "(%g)", prop);
- g_string_append (string, " =");
+ ds_put_cstr (&str, " =");
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (scd->var_view), 0, string);
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (scd->var_view), 0, &str);
if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->cutpoint_button)))
{
const gchar *cutpoint = gtk_entry_get_text (GTK_ENTRY (scd->cutpoint_entry));
- g_string_append_printf (string, "(%s)", cutpoint);
+ ds_put_c_format (&str, "(%s)", cutpoint);
}
- g_string_append (string, ".\n");
+ ds_put_cstr (&str, ".\n");
- text = string->str;
+ text = ds_steal_cstr (&str);
- g_string_free (string, FALSE);
+ ds_destroy (&str);
return text;
}
#include "psppire-dialog.h"
#include "builder-wrapper.h"
#include "psppire-scanf.h"
+#include <libpspp/str.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
PsppireDialogActionFactor *rd = PSPPIRE_DIALOG_ACTION_FACTOR (act);
gchar *text = NULL;
- GString *string = g_string_new ("FACTOR ");
+ struct string str;
+ ds_init_cstr (&str, "FACTOR ");
- g_string_append (string, "\n\t/VARIABLES=");
+ ds_put_cstr (&str, "\n\t/VARIABLES=");
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (rd->variables), 0, string);
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (rd->variables), 0, &str);
- g_string_append (string, "\n\t/CRITERIA = ");
+ ds_put_cstr (&str, "\n\t/CRITERIA = ");
if ( rd->extraction.explicit_nfactors )
- g_string_append_printf (string, "FACTORS (%d)", rd->extraction.n_factors);
+ ds_put_c_format (&str, "FACTORS (%d)", rd->extraction.n_factors);
else
- g_string_append_printf (string, "MINEIGEN (%g)", rd->extraction.mineigen);
+ ds_put_c_format (&str, "MINEIGEN (%g)", rd->extraction.mineigen);
/*
The CRITERIA = ITERATE subcommand is overloaded.
It applies to the next /ROTATION and/or EXTRACTION command whatever comes first.
*/
- g_string_append_printf (string, " ITERATE (%d)", rd->extraction.n_iterations);
+ ds_put_c_format (&str, " ITERATE (%d)", rd->extraction.n_iterations);
- g_string_append (string, "\n\t/EXTRACTION =");
+ ds_put_cstr (&str, "\n\t/EXTRACTION =");
if ( rd->extraction.paf)
- g_string_append (string, "PAF");
+ ds_put_cstr (&str, "PAF");
else
- g_string_append (string, "PC");
+ ds_put_cstr (&str, "PC");
- g_string_append (string, "\n\t/METHOD = ");
+ ds_put_cstr (&str, "\n\t/METHOD = ");
if ( rd->extraction.covariance )
- g_string_append (string, "COVARIANCE");
+ ds_put_cstr (&str, "COVARIANCE");
else
- g_string_append (string, "CORRELATION");
-
-
+ ds_put_cstr (&str, "CORRELATION");
if ( rd->extraction.scree )
{
- g_string_append (string, "\n\t/PLOT = ");
- g_string_append (string, "EIGEN");
+ ds_put_cstr (&str, "\n\t/PLOT = ");
+ ds_put_cstr (&str, "EIGEN");
}
- g_string_append (string, "\n\t/PRINT = ");
- g_string_append (string, "INITIAL ");
+ ds_put_cstr (&str, "\n\t/PRINT = ");
+ ds_put_cstr (&str, "INITIAL ");
if ( rd->extraction.unrotated )
- g_string_append (string, "EXTRACTION ");
+ ds_put_cstr (&str, "EXTRACTION ");
if ( rd->rotation.rotated_solution )
- g_string_append (string, "ROTATION");
+ ds_put_cstr (&str, "ROTATION");
/* The CRITERIA = ITERATE subcommand is overloaded.
It applies to the next /ROTATION and/or EXTRACTION command whatever comes first.
*/
- g_string_append_printf (string, "\n\t/CRITERIA = ITERATE (%d)", rd->rotation.iterations );
+ ds_put_c_format (&str, "\n\t/CRITERIA = ITERATE (%d)", rd->rotation.iterations );
- g_string_append (string, "\n\t/ROTATION = ");
- g_string_append (string, rot_method_syntax[rd->rotation.method]);
+ ds_put_cstr (&str, "\n\t/ROTATION = ");
+ ds_put_cstr (&str, rot_method_syntax[rd->rotation.method]);
- g_string_append (string, ".");
- text = string->str;
+ ds_put_cstr (&str, ".");
+ text = ds_steal_cstr (&str);
- g_string_free (string, FALSE);
+ ds_destroy (&str);
return text;
}
gboolean ok;
GtkTreeIter iter;
guint selected = 0;
+ struct string str;
- GString *string = g_string_new ("FREQUENCIES");
+ ds_init_cstr (&str, "FREQUENCIES");
- g_string_append (string, "\n\t/VARIABLES=");
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (fd->stat_vars), 0, string);
+ ds_put_cstr (&str, "\n\t/VARIABLES=");
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (fd->stat_vars), 0, &str);
- g_string_append (string, "\n\t/FORMAT=");
+ ds_put_cstr (&str, "\n\t/FORMAT=");
switch (fd->tables_opts_order)
{
case FRQ_AVALUE:
- g_string_append (string, "AVALUE");
+ ds_put_cstr (&str, "AVALUE");
break;
case FRQ_DVALUE:
- g_string_append (string, "DVALUE");
+ ds_put_cstr (&str, "DVALUE");
break;
case FRQ_ACOUNT:
- g_string_append (string, "AFREQ");
+ ds_put_cstr (&str, "AFREQ");
break;
case FRQ_DCOUNT:
- g_string_append (string, "DFREQ");
+ ds_put_cstr (&str, "DFREQ");
break;
default:
g_assert_not_reached ();
}
- g_string_append (string, " ");
+ ds_put_cstr (&str, " ");
switch (fd->tables_opts_table)
{
case FRQ_TABLE:
- g_string_append (string, "TABLE");
+ ds_put_cstr (&str, "TABLE");
break;
case FRQ_NOTABLE:
- g_string_append (string, "NOTABLE");
+ ds_put_cstr (&str, "NOTABLE");
break;
case FRQ_LIMIT:
- g_string_append_printf (string, "LIMIT (%d)", fd->tables_opts_limit);
+ ds_put_c_format (&str, "LIMIT (%d)", fd->tables_opts_limit);
break;
}
if (selected != B_FS_DEFAULT)
{
- g_string_append (string, "\n\t/STATISTICS=");
+ ds_put_cstr (&str, "\n\t/STATISTICS=");
if (selected == B_FS_ALL)
- g_string_append (string, "ALL");
+ ds_put_cstr (&str, "ALL");
else if (selected == 0)
- g_string_append (string, "NONE");
+ ds_put_cstr (&str, "NONE");
else
{
int n = 0;
if ((selected & B_FS_DEFAULT) == B_FS_DEFAULT)
{
- g_string_append (string, "DEFAULT");
+ ds_put_cstr (&str, "DEFAULT");
selected &= ~B_FS_DEFAULT;
n++;
}
if (selected & (1u << i))
{
if (n++)
- g_string_append (string, " ");
- g_string_append (string, stats[i].name);
+ ds_put_cstr (&str, " ");
+ ds_put_cstr (&str, stats[i].name);
}
}
}
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->include_missing)))
- g_string_append (string, "\n\t/MISSING=INCLUDE");
+ ds_put_cstr (&str, "\n\t/MISSING=INCLUDE");
if (fd->charts_opts_draw_hist)
{
- g_string_append (string, "\n\t/HISTOGRAM=");
- g_string_append (string,
+ ds_put_cstr (&str, "\n\t/HISTOGRAM=");
+ ds_put_cstr (&str,
fd->charts_opts_draw_normal ? "NORMAL" : "NONORMAL");
if (fd->charts_opts_scale == FRQ_PERCENT)
- g_string_append (string, " PERCENT");
+ ds_put_cstr (&str, " PERCENT");
if (fd->charts_opts_use_min)
- g_string_append_printf (string, " MIN(%.15g)", fd->charts_opts_min);
+ ds_put_c_format (&str, " MIN(%.15g)", fd->charts_opts_min);
if (fd->charts_opts_use_max)
- g_string_append_printf (string, " MAX(%.15g)", fd->charts_opts_max);
+ ds_put_c_format (&str, " MAX(%.15g)", fd->charts_opts_max);
}
if (fd->charts_opts_draw_pie)
{
- g_string_append (string, "\n\t/PIECHART=");
+ ds_put_cstr (&str, "\n\t/PIECHART=");
if (fd->charts_opts_pie_include_missing)
- g_string_append (string, " MISSING");
+ ds_put_cstr (&str, " MISSING");
if (fd->charts_opts_use_min)
- g_string_append_printf (string, " MIN(%.15g)", fd->charts_opts_min);
+ ds_put_c_format (&str, " MIN(%.15g)", fd->charts_opts_min);
if (fd->charts_opts_use_max)
- g_string_append_printf (string, " MAX(%.15g)", fd->charts_opts_max);
+ ds_put_c_format (&str, " MAX(%.15g)", fd->charts_opts_max);
}
- g_string_append (string, ".\n");
+ ds_put_cstr (&str, ".\n");
- text = string->str;
+ text = ds_steal_cstr (&str);
- g_string_free (string, FALSE);
+ ds_destroy (&str);
return text;
}
{
PsppireDialogActionLogistic *rd = PSPPIRE_DIALOG_ACTION_LOGISTIC (a);
gchar *text = NULL;
+ struct string str;
+ const gchar *dep = gtk_entry_get_text (GTK_ENTRY (rd->dep_var));
- GString *string = g_string_new ("LOGISTIC REGRESSION ");
+ ds_init_cstr (&str, "LOGISTIC REGRESSION ");
- const gchar *dep = gtk_entry_get_text (GTK_ENTRY (rd->dep_var));
+ ds_put_cstr (&str, dep);
- g_string_append (string, dep);
+ ds_put_cstr (&str, " WITH ");
- g_string_append (string, " WITH ");
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (rd->indep_vars), 0, &str);
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (rd->indep_vars), 0, string);
+ ds_put_cstr (&str, "\n\t/CRITERIA =");
- g_string_append (string, "\n\t/CRITERIA =");
+ syntax_gen_pspp (&str, " CUT(%g)", rd->cut_point);
- g_string_append_printf (string, " CUT(%g)", rd->cut_point);
- g_string_append_printf (string, " ITERATE(%d)", rd->max_iterations);
+ syntax_gen_pspp (&str, " ITERATE(%d)", rd->max_iterations);
if (rd->conf)
{
- g_string_append_printf (string, "\n\t/PRINT = CI(%g)", rd->conf_level);
+ syntax_gen_pspp (&str, "\n\t/PRINT = CI(%g)", rd->conf_level);
}
if (rd->constant)
- g_string_append (string, "\n\t/NOORIGIN");
+ ds_put_cstr (&str, "\n\t/NOORIGIN");
else
- g_string_append (string, "\n\t/ORIGIN");
+ ds_put_cstr (&str, "\n\t/ORIGIN");
- g_string_append (string, ".\n");
+ ds_put_cstr (&str, ".\n");
- text = string->str;
+ text = ds_steal_cstr (&str);
- g_string_free (string, FALSE);
+ ds_destroy (&str);
return text;
}
#include "gl/error.h"
#include "gl/tmpdir.h"
#include "gl/xalloc.h"
+#include "gl/c-xvasprintf.h"
#include "helper.h"
NULL));
}
-
\f
static void
create_xr_print_driver (GtkPrintContext *context, PsppireOutputWindow *window)
string_map_init (&options);
string_map_insert_nocopy (&options, xstrdup ("paper-size"),
- xasprintf("%.2fx%.2fmm", width, height));
+ c_xasprintf("%.2fx%.2fmm", width, height));
string_map_insert_nocopy (&options, xstrdup ("left-margin"),
- xasprintf ("%.2fmm", left_margin));
+ c_xasprintf ("%.2fmm", left_margin));
string_map_insert_nocopy (&options, xstrdup ("right-margin"),
- xasprintf ("%.2fmm", right_margin));
+ c_xasprintf ("%.2fmm", right_margin));
string_map_insert_nocopy (&options, xstrdup ("top-margin"),
- xasprintf ("%.2fmm", top_margin));
+ c_xasprintf ("%.2fmm", top_margin));
string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
- xasprintf ("%.2fmm", bottom_margin));
+ c_xasprintf ("%.2fmm", bottom_margin));
window->print_xrd =
xr_driver_create (gtk_print_context_get_cairo_context (context), &options);
/* Generate a syntax fragment for NV and append it to STR */
void
-old_value_append_syntax (GString *str, const struct old_value *ov)
+old_value_append_syntax (struct string *str, const struct old_value *ov)
{
switch (ov->type)
{
case OV_NUMERIC:
- g_string_append_printf (str, "%g", ov->v.v);
+ ds_put_c_format (str, "%g", ov->v.v);
break;
case OV_STRING:
{
struct string ds = DS_EMPTY_INITIALIZER;
syntax_gen_string (&ds, ss_cstr (ov->v.s));
- g_string_append (str, ds_cstr (&ds));
+ ds_put_cstr (str, ds_cstr (&ds));
ds_destroy (&ds);
}
break;
case OV_MISSING:
- g_string_append (str, "MISSING");
+ ds_put_cstr (str, "MISSING");
break;
case OV_SYSMIS:
- g_string_append (str, "SYSMIS");
+ ds_put_cstr (str, "SYSMIS");
break;
case OV_ELSE:
- g_string_append (str, "ELSE");
+ ds_put_cstr (str, "ELSE");
break;
case OV_RANGE:
- g_string_append_printf (str, "%g THRU %g",
+ ds_put_c_format (str, "%g THRU %g",
ov->v.range[0],
ov->v.range[1]);
break;
case OV_LOW_UP:
- g_string_append_printf (str, "LOWEST THRU %g",
+ ds_put_c_format (str, "LOWEST THRU %g",
ov->v.range[1]);
break;
case OV_HIGH_DOWN:
- g_string_append_printf (str, "%g THRU HIGHEST",
+ ds_put_c_format (str, "%g THRU HIGHEST",
ov->v.range[0]);
break;
default:
g_warning ("Invalid type in old recode value");
- g_string_append (str, "???");
+ ds_put_cstr (str, "???");
break;
};
}
GType old_value_get_type (void);
-void old_value_append_syntax (GString *str, const struct old_value *ov);
+struct string;
+void old_value_append_syntax (struct string *str, const struct old_value *ov);
void psppire_val_chooser_get_status (PsppireValChooser *vr, struct old_value *ov);
void psppire_val_chooser_set_status (PsppireValChooser *vr, const struct old_value *ov);
#include "psppire-var-ptr.h"
#include "psppire-select-dest.h"
+#include <libpspp/str.h>
#include <data/variable.h>
#include <gettext.h>
return n_vars;
}
+
+
+/*
+ Append the names of selected variables to STR
+ Returns the number of variables appended.
+*/
+gint
+psppire_var_view_append_names_str (PsppireVarView *vv, gint column, struct string *str)
+{
+ gint n_vars = 0;
+ GtkTreeIter iter;
+
+ if ( psppire_var_view_get_iter_first (vv, &iter) )
+ {
+ do
+ {
+ const struct variable *var = psppire_var_view_get_variable (vv, column, &iter);
+ ds_put_cstr (str, " ");
+ ds_put_cstr (str, var_get_name (var));
+
+ n_vars++;
+ }
+ while (psppire_var_view_get_iter_next (vv, &iter));
+ }
+
+ return n_vars;
+}
+
+
+
GType psppire_var_view_get_type (void);
gint psppire_var_view_append_names (PsppireVarView *vv, gint column, GString *string);
+struct string;
+gint psppire_var_view_append_names_str (PsppireVarView *vv, gint column, struct string *);
gboolean psppire_var_view_get_iter_first (PsppireVarView *vv, GtkTreeIter *iter);
/* Generate a syntax fragment for NV and append it to STR */
static void
-new_value_append_syntax (GString *str, const struct new_value *nv)
+new_value_append_syntax (struct string *dds, const struct new_value *nv)
{
switch (nv->type)
{
case NV_NUMERIC:
- g_string_append_printf (str, "%g", nv->v.v);
+ ds_put_c_format (dds, "%g", nv->v.v);
break;
case NV_STRING:
- {
- struct string ds = DS_EMPTY_INITIALIZER;
- syntax_gen_string (&ds, ss_cstr (nv->v.s));
- g_string_append (str, ds_cstr (&ds));
- ds_destroy (&ds);
- }
+ syntax_gen_string (dds, ss_cstr (nv->v.s));
break;
case NV_COPY:
- g_string_append (str, "COPY");
+ ds_put_cstr (dds, "COPY");
break;
case NV_SYSMIS:
- g_string_append (str, "SYSMIS");
+ ds_put_cstr (dds, "SYSMIS");
break;
default:
/* Shouldn't ever happen */
g_warning ("Invalid type in new recode value");
- g_string_append (str, "???");
+ ds_put_cstr (dds, "???");
break;
}
}
gboolean ok;
GtkTreeIter iter;
gchar *text;
+ struct string dds;
+
+ ds_init_empty (&dds);
- GString *str = g_string_sized_new (100);
/* Declare new string variables if applicable */
if ( rd->different &&
g_hash_table_iter_init (&iter, rd->varmap);
while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
{
- g_string_append (str, "\nSTRING ");
- g_string_append (str, nlp->name);
- g_string_append_printf (str, " (A%d).",
+ ds_put_cstr (&dds, "\nSTRING ");
+ ds_put_cstr (&dds, nlp->name);
+ ds_put_c_format (&dds, " (A%d).",
(int)
gtk_spin_button_get_value (GTK_SPIN_BUTTON (rd->width_entry) )
);
}
}
- g_string_append (str, "\nRECODE ");
+ ds_put_cstr (&dds, "\nRECODE ");
- psppire_var_view_append_names (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, str);
+ psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &dds);
- g_string_append (str, "\n\t");
+ ds_put_cstr (&dds, "\n\t");
if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->convert_button)))
{
- g_string_append (str, "(CONVERT) ");
+ ds_put_cstr (&dds, "(CONVERT) ");
}
for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map),
ov = g_value_get_boxed (&ov_value);
nv = g_value_get_boxed (&nv_value);
- g_string_append (str, "(");
+ ds_put_cstr (&dds, "(");
- old_value_append_syntax (str, ov);
- g_string_append (str, " = ");
- new_value_append_syntax (str, nv);
+ old_value_append_syntax (&dds, ov);
+ ds_put_cstr (&dds, " = ");
+ new_value_append_syntax (&dds, nv);
- g_string_append (str, ") ");
+ ds_put_cstr (&dds, ") ");
g_value_unset (&ov_value);
g_value_unset (&nv_value);
}
{
GtkTreeIter iter;
- g_string_append (str, "\n\tINTO ");
+ ds_put_cstr (&dds, "\n\tINTO ");
for (ok = psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter);
ok;
nlp = g_hash_table_lookup (rd->varmap, var);
- g_string_append (str, nlp->name);
- g_string_append (str, " ");
+ ds_put_cstr (&dds, nlp->name);
+ ds_put_cstr (&dds, " ");
}
}
- g_string_append (str, ".");
+ ds_put_cstr (&dds, ".");
/* If applicable, set labels for the new variables. */
if ( rd->different )
struct string sl;
ds_init_empty (&sl);
syntax_gen_string (&sl, ss_cstr (nlp->label));
- g_string_append_printf (str, "\nVARIABLE LABELS %s %s.",
+ ds_put_c_format (&dds, "\nVARIABLE LABELS %s %s.",
nlp->name, ds_cstr (&sl));
ds_destroy (&sl);
}
}
- g_string_append (str, "\nEXECUTE.\n");
+ ds_put_cstr (&dds, "\nEXECUTE.\n");
- text = str->str;
+ text = ds_steal_cstr (&dds);
- g_string_free (str, FALSE);
+ ds_destroy (&dds);
return text;
}
generate_syntax_filter (const struct select_cases_dialog *scd)
{
gchar *text = NULL;
- GString *string = g_string_new ("");
+ struct string dss;
const gchar *filter = "filter_$";
const gchar key[]="case_$";
- if ( gtk_toggle_button_get_active
+ ds_init_empty (&dss);
+
+ if (gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
"radiobutton-range"))))
{
GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
"range-dialog-last"));
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE filter_$ = ($CASENUM >= %ld "
"AND $CASENUM <= %ld).\n",
(long) gtk_spin_button_get_value (first),
(long) gtk_spin_button_get_value (last)
);
- g_string_append (string, "EXECUTE.\n");
+ ds_put_cstr (&dss, "EXECUTE.\n");
}
else if ( gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
const double percentage =
gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE %s = RV.UNIFORM (0,1) < %g.\n",
filter,
percentage / 100.0 );
const gchar ranvar[]="rv_$";
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE %s = $CASENUM.\n", key);
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE %s = %s > %d.\n",
filter, key, from_n_cases);
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE %s = RV.UNIFORM (0, 1).\n",
ranvar);
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"SORT BY %s, %s.\n",
filter, ranvar);
- g_string_append (string, "EXECUTE.\n");
+ ds_put_cstr (&dss, "EXECUTE.\n");
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE %s = $CASENUM.\n",
filter );
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE %s = %s <= %d\n",
filter,
filter,
n_cases );
- g_string_append (string, "EXECUTE.\n");
+ ds_put_cstr (&dss, "EXECUTE.\n");
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"SORT BY %s.\n",
key);
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"DELETE VARIABLES %s, %s.\n",
key, ranvar);
-
}
- g_string_append (string, "EXECUTE.\n");
-
+ ds_put_cstr (&dss, "EXECUTE.\n");
}
else
{
filter = gtk_entry_get_text (entry);
}
+ ds_put_c_format (&dss, "FILTER BY %s.\n", filter);
+
+ text = ds_steal_cstr (&dss);
- g_string_append_printf (string, "FILTER BY %s.\n", filter);
+ ds_destroy (&dss);
- text = string->str;
- g_string_free (string, FALSE);
return text;
}
generate_syntax_delete (const struct select_cases_dialog *scd)
{
gchar *text = NULL;
- GString *string = NULL;
+ struct string dss;
if ( gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
return xstrdup ("\n");
}
- string = g_string_new ("");
+ ds_init_empty (&dss);
if ( gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
get_widget_assert (scd->xml,
"radiobutton-sample-percent");
- g_string_append (string, "SAMPLE ");
+ ds_put_cstr (&dss, "SAMPLE ");
if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
{
const double percentage =
gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
- g_string_append_printf (string, "%g.", percentage / 100.0);
+ ds_put_c_format (&dss, "%g.", percentage / 100.0);
}
else
{
const gint from_n_cases =
gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
- g_string_append_printf (string, "%d FROM %d .", n_cases, from_n_cases);
+ ds_put_c_format (&dss, "%d FROM %d .", n_cases, from_n_cases);
}
}
GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
"range-dialog-last"));
- g_string_append_printf (string,
+ ds_put_c_format (&dss,
"COMPUTE filter_$ = ($CASENUM >= %ld "
"AND $CASENUM <= %ld).\n",
(long) gtk_spin_button_get_value (first),
(long) gtk_spin_button_get_value (last)
);
- g_string_append (string, "EXECUTE.\n");
- g_string_append_printf (string, "SELECT IF filter_$.\n");
+ ds_put_cstr (&dss, "EXECUTE.\n");
+ ds_put_c_format (&dss, "SELECT IF filter_$.\n");
}
else if ( gtk_toggle_button_get_active
GTK_ENTRY (get_widget_assert (scd->xml,
"filter-variable-entry"));
- g_string_append_printf (string, "SELECT IF (%s <> 0).",
+ ds_put_c_format (&dss, "SELECT IF (%s <> 0).",
gtk_entry_get_text (entry));
}
- g_string_append (string, "\n");
+ ds_put_cstr (&dss, "\n");
+ text = ds_steal_cstr (&dss);
+ ds_destroy (&dss);
- text = string->str;
- g_string_free (string, FALSE);
return text;
}
void
tt_options_dialog_append_syntax (const struct tt_options_dialog *tto, GString *str)
{
- g_string_append (str, "\t/MISSING=");
+ struct string dss;
+ ds_init_empty (&dss);
- if ( tto->excl == EXCL_ANALYSIS )
- g_string_append (str, "ANALYSIS");
+ ds_put_cstr (&dss, "\t/MISSING=");
+
+ if (tto->excl == EXCL_ANALYSIS)
+ ds_put_cstr (&dss, "ANALYSIS");
else
- g_string_append (str, "LISTWISE");
+ ds_put_cstr (&dss, "LISTWISE");
+
+ ds_put_c_format (&dss, "\n\t/CRITERIA=CIN(%g)",
+ tto->confidence_interval/100.0);
+ g_string_append (str, ds_cstr (&dss));
- g_string_append_printf (str, "\n\t/CRITERIA=CIN(%g)",
- tto->confidence_interval/100.0);
+ ds_destroy (&dss);
}
#include "libpspp/i18n.h"
#include "libpspp/message.h"
#include "libpspp/str.h"
+#include "libpspp/misc.h"
#include "gl/ftoastr.h"
{
char s[DBL_BUFSIZE_BOUND];
- dtoastr (s, sizeof s, 0, 0, number);
+ c_dtoastr (s, sizeof s, 0, 0, number);
ds_put_cstr (output, s);
}
}
{
for (;;)
{
+ char directive;
size_t copy = strcspn (format, "%");
ds_put_substring (output, ss_buffer (format, copy));
format += copy;
return;
assert (*format == '%');
format++;
- switch (*format++)
+ directive = *format++;
+ switch (directive)
{
case 's':
{
break;
case 'f':
+ case 'g':
{
+ char conv[3];
double d = va_arg (args, double);
- switch (*format++)
- {
- case 'p':
- ds_put_format (output, "%f", d);
- break;
- default:
- NOT_REACHED ();
- }
+ conv[0]='%';
+ conv[1]=directive;
+ conv[2]='\0';
+ ds_put_c_format (output, conv, d);
break;
}
tests/data/data-in.at \
tests/data/data-out.at \
tests/data/datasheet-test.at \
+ tests/data/dictionary.at \
tests/data/format-guesser.at \
tests/data/por-file.at \
tests/data/sys-file-reader.at \
--- /dev/null
+AT_BANNER([dictionary])
+
+AT_SETUP([dictionary case-insensitivity])
+AT_DATA([dictionary.sps], [dnl
+DATA LIST LIST /aèiöu aeiou.
+BEGIN DATA
+1 2
+END DATA.
+LIST AÈIÖU
+RENAME VARIABLE (aèiöu=AÈIÖU).
+LIST.
+RENAME VARIABLE (aeiou=aèiöu).
+])
+AT_CLEANUP
,Missing Values: 1 THRU 3; 5,,
num9,Format: F8.0,,9
,Missing Values: 1 THRU HIGHEST; -5,,
-numÃ\80Ã\88Ã\8cÃ\91Ã\92,Format: F8.0,,10
+numà èìñò,Format: F8.0,,10
,Missing Values: LOWEST THRU 1; 5,,
str1,Format: A4,,11
str2,String variable 2's label,,12
,Format: A25,,
Table: Data List
-num1,num2,num3,num4,num5,num6,num7,num8,num9,numÃ\80Ã\88Ã\8cÃ\91Ã\92,str1,str2,str3,str4,str5,str6,str7,str8
+num1,num2,num3,num4,num5,num6,num7,num8,num9,numà èìñò,str1,str2,str3,str4,str5,str6,str7,str8
1,2,3,4,5,6,7,8,9,10,abcd,efgh,ijkl,mnop,qrst,uvwx,yzABCDEFGHI,JKLMNOPQRSTUVWXYZ01234567
])
done
AT_CHECK([pspp -o pspp.csv sys-file.sps])
AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
Variable,Description,,Position
-sÃ\89q256,Format: A256,,1
+séq256,Format: A256,,1
str600,Format: A600,,2
Table: Data List
-sÃ\89q256,str600
+séq256,str600
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@a,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyz
])
done
])
AT_DATA([b.data], [dnl
1bN
-3bO
+3 O
4bP
6bQ
7bR
BY a.
LIST.
])
+ cat update.sps
AT_CHECK([pspp -O format=csv update.sps], [0], [dnl
update.sps:6: warning: UPDATE: Encountered 3 sets of duplicate cases in the master file.
1,b,B,N,1,1
1,a,C,,1,0
2,a,D,,1,0
-3,b,E,O,1,1
+3,a,E,O,1,1
4,b,F,P,1,1
5,a,G,,1,0
5,a,H,,1,0
AT_CLEANUP
+
+
+AT_SETUP([NPAR TESTS CHISQUARE crash])
+dnl This syntax had been observed to crash pspp
+
+AT_DATA([npar.sps], [dnl
+data list list /x *.
+begin data.
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+end data.
+
+* This happens to be invalid syntax. But should not crash.
+NPAR TEST
+ /CHISQUARE= x(0.098, 99.098)
+ /EXPECTED = 1.2.
+])
+
+AT_CHECK([pspp -O format=csv npar.sps], [1], [ignore])
+
+AT_CLEANUP
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/hash-functions.h"
#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
#include "libpspp/str.h"
#include "libpspp/string-set.h"
#include "libpspp/stringi-set.h"
node = stringi_map_find_node (map, key);
check (node != NULL);
- check (!strcasecmp (key, stringi_map_node_get_key (node)));
+ check (!utf8_strcasecmp (key, stringi_map_node_get_key (node)));
check (!strcmp (value, stringi_map_node_get_value (node)));
check (node == stringi_map_insert (map, key, "012"));
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <string.h>
#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
#include "libpspp/str.h"
\f
/* Exit with a failure code.
node = stringi_set_find_node (set, string);
check (node != NULL);
- check (!strcasecmp (string, stringi_set_node_get_string (node)));
+ check (!utf8_strcasecmp (string, stringi_set_node_get_string (node)));
}
/* Checks that SET contains the CNT strings in DATA, that its structure is
check (s == array[i]);
for (j = 0; j < left; j++)
- if (!strcasecmp (s, make_string (data_copy[j])))
+ if (!utf8_strcasecmp (s, make_string (data_copy[j])))
{
data_copy[j] = data_copy[--left];
goto next;
for (i = 0; i < cnt; i++)
{
if (i > 0)
- check (strcasecmp (array[i - 1], array[i]) < 0);
+ check (utf8_strcasecmp (array[i - 1], array[i]) < 0);
check (stringi_set_contains (set, array[i]));
}
free (array);
])
AT_CLEANUP
+AT_SETUP([ASCII driver u8_line_set_length])
+AT_KEYWORDS([render rendering])
+AT_DATA([input], [dnl
+0 0 0 àéî
+0 1 0 àéî
+0 2 0 àéî
+0 3 0 àéî
+0 4 0 àéî
+set-length 0 4
+set-length 1 3
+set-length 2 2
+set-length 3 1
+set-length 4 0
+
+0 6 0 あい
+0 7 0 あい
+0 8 0 あい
+0 9 0 あい
+0 10 0 あい
+0 11 0 あい
+set-length 6 5
+set-length 7 4
+set-length 8 3
+set-length 9 2
+set-length 10 1
+set-length 11 0
+])
+AT_CHECK([render-test --draw-mode input], [0], [dnl
+àéî
+àéî
+àé
+à
+
+あい
+あい
+あ?
+あ
+?
+])
+AT_CLEANUP
+
AT_SETUP([ASCII driver Unicode box characters])
AT_KEYWORDS([render rendering])
AT_DATA([input], [3 3
/* PSPP - a program for statistical analysis.
- Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
while (fgets (buffer, sizeof buffer, stream))
{
char text[sizeof buffer];
+ int length;
int emph;
int x, y;
if (strchr ("#\r\n", buffer[0]))
continue;
- if (sscanf (buffer, "%d %d %d %[^\n]", &x, &y, &emph, text) != 4)
+ if (sscanf (buffer, "%d %d %d %[^\n]", &x, &y, &emph, text) == 4)
+ ascii_test_write (ascii_driver, text, x, y, emph ? TAB_EMPH : 0);
+ else if (sscanf (buffer, "set-length %d %d", &y, &length) == 2)
+ ascii_test_set_length (ascii_driver, y, length);
+ else
error (1, 0, "line %d has invalid format", line);
-
- ascii_test_write (ascii_driver, text, x, y, emph ? TAB_EMPH : 0);
}
}