X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Foutput.c;h=9527c46f210e5994624964c4f7cdc2cc9318463f;hb=5de8102af0956488f48ae9bf4941e5867a0f1260;hp=349b5d3c3212b386f978d8dd6318dece52c33a07;hpb=d8dd3a226c9b963314bbe6a2ed2cf74714072c77;p=pspp-builds.git diff --git a/src/output/output.c b/src/output/output.c index 349b5d3c..9527c46f 100644 --- a/src/output/output.c +++ b/src/output/output.c @@ -1,21 +1,18 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2007 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 2 of the - License, or (at your option) any later version. + 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. + 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include #include "output.h" @@ -24,7 +21,7 @@ #include #include #include -#include +#include #include "htmlP.h" #include "intprops.h" #include @@ -70,12 +67,12 @@ static struct outp_names *outp_configure_vec; /* A list of driver classes. */ struct outp_driver_class_list { - struct outp_class *class; + const struct outp_class *class; struct outp_driver_class_list *next; }; -struct outp_driver_class_list *outp_class_list; -struct outp_driver *outp_driver_list; +static struct outp_driver_class_list *outp_class_list; +static struct outp_driver *outp_driver_list; char *outp_title; char *outp_subtitle; @@ -85,13 +82,12 @@ char *outp_subtitle; static int disabled_devices; static void destroy_driver (struct outp_driver *); -static void configure_driver_line (struct string *); -static void configure_driver (const struct string *, const struct string *, - const struct string *, const struct string *); +static void configure_driver (const struct substring, const struct substring, + const struct substring, const struct substring); /* Add a class to the class list. */ static void -add_class (struct outp_class *class) +add_class (const struct outp_class *class) { struct outp_driver_class_list *new_list = xmalloc (sizeof *new_list); @@ -153,8 +149,8 @@ add_name (char *bp, char *ep, int source) outp_configure_vec = n; } -/* Checks that outp_configure_vec is empty, bitches & clears it if it - isn't. */ +/* Checks that outp_configure_vec is empty, complains and clears + it if it isn't. */ static void check_configure_vec (void) { @@ -206,7 +202,7 @@ find_defn_value (const char *key) for (d = outp_macros; d; d = d->next) if (!strcmp (key, d->key)) - return ds_c_str(&d->value); + return ds_cstr (&d->value); if (!strcmp (key, "viewwidth")) { sprintf (buf, "%d", get_viewwidth ()); @@ -227,7 +223,6 @@ outp_init (void) { extern struct outp_class ascii_class; extern struct outp_class postscript_class; - extern struct outp_class html_class; char def[] = "default"; @@ -254,17 +249,13 @@ delete_macros (void) } static void -init_default_drivers (void) +init_default_drivers (void) { - struct string s; - error (0, 0, _("using default output driver configuration")); - - ds_create (&s, - "list:ascii:listing:" - "length=66 width=79 output-file=\"pspp.list\""); - configure_driver_line (&s); - ds_destroy (&s); + configure_driver (ss_cstr ("list"), + ss_cstr ("ascii"), + ss_cstr ("listing"), + ss_cstr ("length=66 width=79 output-file=\"pspp.list\"")); } /* Reads the initialization file; initializes @@ -283,10 +274,9 @@ outp_read_devices (void) init_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_INIT_FILE", "devices"), fn_getenv_default ("STAT_OUTPUT_INIT_PATH", - config_path), - NULL); + config_path)); - ds_init (&line, 128); + ds_init_empty (&line); if (init_fn == NULL) { @@ -307,13 +297,13 @@ outp_read_devices (void) { char *cp; - if (!ds_get_config_line (f, &line, &line_number)) + if (!ds_read_config_line (&line, &line_number, f)) { if (ferror (f)) error (0, errno, _("reading \"%s\""), init_fn); break; } - for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++); + for (cp = ds_cstr (&line); isspace ((unsigned char) *cp); cp++); if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6])) outp_configure_macro (&cp[7]); else if (*cp) @@ -327,7 +317,7 @@ outp_read_devices (void) struct outp_names *n = search_names (cp, ep); if (n) { - configure_driver_line (&line); + outp_configure_driver_line (ds_ss (&line)); delete_name (n); } } @@ -346,10 +336,10 @@ exit: ds_destroy (&line); delete_macros (); - if (result) + if (result) { - if (outp_driver_list == NULL) - error (0, 0, _("no active output drivers")); + if (outp_driver_list == NULL) + error (0, 0, _("no active output drivers")); } else error (0, 0, _("error reading device definition file")); @@ -409,14 +399,14 @@ outp_configure_macro (char *bp) free (d); return; } - + if (*ep == '=') ep++; while (isspace ((unsigned char) *ep)) ep++; - ds_create(&d->value, ep); - fn_interp_vars(&d->value, find_defn_value); + ds_init_cstr (&d->value, ep); + fn_interp_vars (ds_ss (&d->value), find_defn_value, &d->value); d->next = outp_macros; d->prev = NULL; if (outp_macros) @@ -444,10 +434,10 @@ destroy_list (struct outp_driver ** dl) void outp_done (void) { - struct outp_driver_class_list *n = outp_class_list ; + struct outp_driver_class_list *n = outp_class_list ; destroy_list (&outp_driver_list); - while (n) + while (n) { struct outp_driver_class_list *next = n->next; free(n); @@ -457,7 +447,7 @@ outp_done (void) free (outp_title); outp_title = NULL; - + free (outp_subtitle); outp_subtitle = NULL; } @@ -485,20 +475,20 @@ outp_list_classes (void) putc('\n', stdout); } -/* Obtains a token from S starting at position *POS, which is - updated. Errors are reported against the given DRIVER_NAME. +/* Obtains a token from S and advances its position. Errors are + reported against the given DRIVER_NAME. The token is stored in TOKEN. Returns true if successful, false on syntax error. Caller is responsible for skipping leading spaces. */ static bool -get_option_token (const struct string *s, const char *driver_name, - size_t *pos, struct string *token) +get_option_token (struct substring *s, const char *driver_name, + struct string *token) { int c; - + ds_clear (token); - c = ds_at (s, *pos); + c = ss_get_char (s); if (c == EOF) { error (0, 0, _("syntax error parsing options for \"%s\" driver"), @@ -509,13 +499,12 @@ get_option_token (const struct string *s, const char *driver_name, { int quote = c; - ++*pos; for (;;) { - c = ds_at (s, (*pos)++); + c = ss_get_char (s); if (c == quote) break; - else if (c == EOF) + else if (c == EOF) { error (0, 0, _("reached end of options inside quoted string " @@ -524,12 +513,13 @@ get_option_token (const struct string *s, const char *driver_name, return false; } else if (c != '\\') - ds_putc (token, c); + ds_put_char (token, c); else { int out; - - switch (ds_at (s, *pos)) + + c = ss_get_char (s); + switch (c) { case '\'': out = '\''; @@ -570,19 +560,15 @@ get_option_token (const struct string *s, const char *driver_name, case '6': case '7': out = c - '0'; - while (ds_at (s, *pos) >= '0' && ds_at (s, *pos) <= '7') - out = c * 8 + ds_at (s, (*pos)++) - '0'; + while (ss_first (*s) >= '0' && ss_first (*s) <= '7') + out = out * 8 + (ss_get_char (s) - '0'); break; case 'x': case 'X': out = 0; - while (isxdigit (ds_at (s, *pos))) + while (isxdigit (ss_first (*s))) { - c = ds_at (s, *pos); - if (!isxdigit (c)) - break; - (*pos)++; - + c = ss_get_char (s); out *= 16; if (isdigit (c)) out += c - '0'; @@ -596,61 +582,63 @@ get_option_token (const struct string *s, const char *driver_name, driver_name); return false; } - ds_putc (token, out); + ds_put_char (token, out); } } } - else + else { - do + for (;;) { - ds_putc (token, c); - c = ds_at (s, ++*pos); + ds_put_char (token, c); + + c = ss_first (*s); + if (c == EOF || c == '=' || isspace (c)) + break; + ss_advance (s, 1); } - while (c != EOF && c != '=' && !isspace (c)); } - + return 1; } bool -outp_parse_options (const struct string *options, +outp_parse_options (struct substring options, bool (*callback) (struct outp_driver *, const char *key, const struct string *value), struct outp_driver *driver) { - struct string key = DS_INITIALIZER; - struct string value = DS_INITIALIZER; - size_t pos = 0; + struct string key = DS_EMPTY_INITIALIZER; + struct string value = DS_EMPTY_INITIALIZER; + struct substring left = options; bool ok = true; do { - pos += ds_span (options, pos, " \t"); - if (ds_at (options, pos) == EOF) + ss_ltrim (&left, ss_cstr (CC_SPACES)); + if (ss_is_empty (left)) break; - - if (!get_option_token (options, driver->name, &pos, &key)) + + if (!get_option_token (&left, driver->name, &key)) break; - pos += ds_span (options, pos, " \t"); - if (ds_at (options, pos) != '=') + ss_ltrim (&left, ss_cstr (CC_SPACES)); + if (!ss_match_char (&left, '=')) { error (0, 0, _("syntax error expecting `=' " "parsing options for driver \"%s\""), driver->name); break; } - pos++; - - pos += ds_span (options, pos, " \t"); - if (!get_option_token (options, driver->name, &pos, &value)) + + ss_ltrim (&left, ss_cstr (CC_SPACES)); + if (!get_option_token (&left, driver->name, &value)) break; - ok = callback (driver, ds_c_str (&key), &value); + ok = callback (driver, ds_cstr (&key), &value); } while (ok); - + ds_destroy (&key); ds_destroy (&value); @@ -669,60 +657,50 @@ find_driver (char *name) return NULL; } -/* String S is in format: - DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS - Adds a driver to outp_driver_list pursuant to the specification - provided. */ +/* Adds a driver to outp_driver_list pursuant to the + specification provided. */ static void -configure_driver (const struct string *driver_name, - const struct string *class_name, - const struct string *device_type, - const struct string *options) +configure_driver (struct substring driver_name, struct substring class_name, + struct substring device_type, struct substring options) { struct outp_driver *d, *iter; struct outp_driver_class_list *c; + + struct substring token; + size_t save_idx = 0; int device; /* Find class. */ for (c = outp_class_list; c; c = c->next) - if (!strcmp (c->class->name, ds_c_str (class_name))) + if (!ss_compare (ss_cstr (c->class->name), class_name)) break; if (c == NULL) { - error (0, 0, _("unknown output driver class `%s'"), - ds_c_str (class_name)); + error (0, 0, _("unknown output driver class `%.*s'"), + (int) ss_length (class_name), ss_data (class_name)); return; } - + /* Parse device type. */ device = 0; - if (device_type != NULL) - { - struct string token = DS_INITIALIZER; - size_t save_idx = 0; - - while (ds_tokenize (device_type, &token, " \t\r\v", &save_idx)) - { - const char *type = ds_c_str (&token); - if (!strcmp (type, "listing")) - device |= OUTP_DEV_LISTING; - else if (!strcmp (type, "screen")) - device |= OUTP_DEV_SCREEN; - else if (!strcmp (type, "printer")) - device |= OUTP_DEV_PRINTER; - else - error (0, 0, _("unknown device type `%s'"), type); - } - ds_destroy (&token); - } + while (ss_tokenize (device_type, ss_cstr (CC_SPACES), &save_idx, &token)) + if (!ss_compare (token, ss_cstr ("listing"))) + device |= OUTP_DEV_LISTING; + else if (!ss_compare (token, ss_cstr ("screen"))) + device |= OUTP_DEV_SCREEN; + else if (!ss_compare (token, ss_cstr ("printer"))) + device |= OUTP_DEV_PRINTER; + else + error (0, 0, _("unknown device type `%.*s'"), + (int) ss_length (token), ss_data (token)); /* Open the device. */ d = xmalloc (sizeof *d); d->next = d->prev = NULL; d->class = c->class; - d->name = xstrdup (ds_c_str (driver_name)); + d->name = ss_xstrdup (driver_name); d->page_open = false; - d->device = OUTP_DEV_NONE; + d->device = device; d->cp_x = d->cp_y = 0; d->ext = NULL; d->prc = NULL; @@ -754,32 +732,31 @@ configure_driver (const struct string *driver_name, DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS Adds a driver to outp_driver_list pursuant to the specification provided. */ -static void -configure_driver_line (struct string *line) +void +outp_configure_driver_line (struct substring line_) { - struct string tokens[4]; + struct string line = DS_EMPTY_INITIALIZER; + struct substring tokens[4]; size_t save_idx; size_t i; - fn_interp_vars (line, find_defn_value); + fn_interp_vars (line_, find_defn_value, &line); save_idx = 0; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { - struct string *token = &tokens[i]; - ds_init (token, 0); - ds_separate (line, token, i < 3 ? ":" : "", &save_idx); - ds_trim_spaces (token); + struct substring *token = &tokens[i]; + ds_separate (&line, ss_cstr (i < 3 ? ":" : ""), &save_idx, token); + ss_trim (token, ss_cstr (CC_SPACES)); } - if (!ds_is_empty (&tokens[0]) && !ds_is_empty (&tokens[1])) - configure_driver (&tokens[0], &tokens[1], &tokens[2], &tokens[3]); + if (!ss_is_empty (tokens[0]) && !ss_is_empty (tokens[1])) + configure_driver (tokens[0], tokens[1], tokens[2], tokens[3]); else error (0, 0, _("driver definition line missing driver name or class name")); - for (i = 0; i < 4; i++) - ds_destroy (&tokens[i]); + ds_destroy (&line); } /* Destroys output driver D. */ @@ -814,7 +791,7 @@ destroy_driver (struct outp_driver *d) code and stores subcategory in *SUBCAT on success. Returns -1 on failure. */ int -outp_match_keyword (const char *s, struct outp_option *tab, int *subcat) +outp_match_keyword (const char *s, const struct outp_option *tab, int *subcat) { for (; tab->keyword != NULL; tab++) if (!strcmp (s, tab->keyword)) @@ -944,9 +921,9 @@ lossage: /* Stores the dimensions in 1/72000" units of paper identified by SIZE, which is of form `HORZ x VERT' or `HORZ by VERT' where each - of HORZ and VERT are dimensions, into *H and *V. Return nonzero on + of HORZ and VERT are dimensions, into *H and *V. Return true on success. */ -static int +static bool internal_get_paper_size (char *size, int *h, int *v) { char *tail; @@ -955,7 +932,7 @@ internal_get_paper_size (char *size, int *h, int *v) size++; *h = outp_evaluate_dimension (size, &tail); if (tail == NULL) - return 0; + return false; while (isspace ((unsigned char) *tail)) tail++; if (*tail == 'x') @@ -965,7 +942,7 @@ internal_get_paper_size (char *size, int *h, int *v) else { error (0, 0, _("`x' expected in paper size `%s'"), size); - return 0; + return false; } *v = outp_evaluate_dimension (tail, &tail); if (tail == NULL) @@ -975,19 +952,19 @@ internal_get_paper_size (char *size, int *h, int *v) if (*tail) { error (0, 0, _("trailing garbage `%s' on paper size `%s'"), tail, size); - return 0; + return false; } - - return 1; + + return true; } /* Stores the dimensions, in 1/72000" units, of paper identified by SIZE into *H and *V. SIZE may be a pair of dimensions of form `H x V', or it may be a case-insensitive paper identifier, which is - looked up in the `papersize' configuration file. Returns nonzero + looked up in the `papersize' configuration file. Returns true on success. May modify SIZE. */ /* Don't read further unless you've got a strong stomach. */ -int +bool outp_get_paper_size (char *size, int *h, int *v) { struct paper_size @@ -1003,8 +980,8 @@ outp_get_paper_size (char *size, int *h, int *v) struct string line; int line_number = 0; - int free_it = 0; - int result = 0; + bool free_it = false; + bool result = false; char *ep; while (isspace ((unsigned char) *size)) @@ -1021,7 +998,7 @@ outp_get_paper_size (char *size, int *h, int *v) error (0, 0, _("paper size name cannot be empty")); return 0; } - + ep++; if (*ep) *ep = 0; @@ -1029,10 +1006,9 @@ outp_get_paper_size (char *size, int *h, int *v) pprsz_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_PAPERSIZE_FILE", "papersize"), fn_getenv_default ("STAT_OUTPUT_INIT_PATH", - config_path), - NULL); + config_path)); - ds_init (&line, 128); + ds_init_empty (&line); if (pprsz_fn == NULL) { @@ -1049,35 +1025,33 @@ outp_get_paper_size (char *size, int *h, int *v) for (;;) { - char *cp, *bp, *ep; + struct substring p, name; - if (!ds_get_config_line (f, &line, &line_number)) + if (!ds_read_config_line (&line, &line_number, f)) { if (ferror (f)) error (0, errno, _("error reading \"%s\""), pprsz_fn); break; } - for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++); - if (*cp == 0) - continue; - if (*cp != '"') - goto lex_error; - for (bp = ep = cp + 1; *ep && *ep != '"'; ep++); - if (!*ep) + + p = ds_ss (&line); + ss_ltrim (&p, ss_cstr (CC_SPACES)); + if (!ss_match_char (&p, '"') || !ss_get_until (&p, '"', &name)) goto lex_error; - *ep = 0; - if (0 != strcasecmp (bp, size)) + if (ss_compare (name, ss_cstr (size))) continue; - for (cp = ep + 1; isspace ((unsigned char) *cp); cp++); - if (*cp == '=') + ss_ltrim (&p, ss_cstr (CC_SPACES)); + if (ss_match_char (&p, '=')) { - size = xmalloc (ep - bp + 1); - strcpy (size, bp); - free_it = 1; + if (free_it) + free (size); + ss_trim (&p, ss_cstr (CC_SPACES)); + size = ss_xstrdup (p); + free_it = true; continue; } - size = &ep[1]; + size = ss_data (p); break; lex_error: @@ -1095,7 +1069,7 @@ exit: if (!result) error (0, 0, _("error reading paper size definition file")); - + return result; } @@ -1106,10 +1080,6 @@ exit: struct outp_driver * outp_drivers (struct outp_driver *d) { -#if DEBUGGING - struct outp_driver *orig_d = d; -#endif - for (;;) { if (d == NULL) @@ -1125,10 +1095,10 @@ outp_drivers (struct outp_driver *d) return d; } -/* Enables (if ENABLE is nonzero) or disables (if ENABLE is zero) the +/* Enables (if ENABLE is true) or disables (if ENABLE is false) the device(s) given in mask DEVICE. */ void -outp_enable_device (int enable, int device) +outp_enable_device (bool enable, int device) { if (enable) disabled_devices &= ~device; @@ -1138,9 +1108,9 @@ outp_enable_device (int enable, int device) /* Opens a page on driver D (if one is not open). */ void -outp_open_page (struct outp_driver *d) +outp_open_page (struct outp_driver *d) { - if (!d->page_open) + if (!d->page_open) { d->cp_x = d->cp_y = 0; @@ -1152,9 +1122,9 @@ outp_open_page (struct outp_driver *d) /* Closes the page on driver D (if one is open). */ void -outp_close_page (struct outp_driver *d) +outp_close_page (struct outp_driver *d) { - if (d->page_open) + if (d->page_open) { if (d->class->close_page != NULL) d->class->close_page (d); @@ -1162,15 +1132,25 @@ outp_close_page (struct outp_driver *d) } } -/* Ejects the paper on device D, if a page is open and is not - blank. */ +/* Ejects the page on device D, if a page is open and non-blank, + and opens a new page. */ void outp_eject_page (struct outp_driver *d) { if (d->page_open && d->cp_y != 0) + outp_close_page (d); + outp_open_page (d); +} + +/* Flushes output to screen devices, so that the user can see + output that doesn't fill up an entire page. */ +void +outp_flush (struct outp_driver *d) +{ + if (d->device & OUTP_DEV_SCREEN && d->class->flush != NULL) { outp_close_page (d); - outp_open_page (d); + d->class->flush (d); } } @@ -1181,10 +1161,10 @@ outp_string_width (struct outp_driver *d, const char *s, enum outp_font font) { struct outp_text text; int width; - + text.font = font; text.justification = OUTP_LEFT; - ls_init (&text.string, (char *) s, strlen (s)); + text.string = ss_cstr (s); text.h = text.v = INT_MAX; d->class->text_metrics (d, &text, &width, NULL);