X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fascii.c;h=7de2d0523a5942dfabcc20bf4ae743c9ba6dfb59;hb=f8ea4bf58da012da87a34d4d0d81ce2874a7c2f3;hp=7804ade3f475d9e0cc08fa281be5a2d5ed6677d5;hpb=94a8e93c4397e1140dd6de5db19d054df546419e;p=pspp diff --git a/src/output/ascii.c b/src/output/ascii.c index 7804ade3f4..7de2d0523a 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -1,5 +1,5 @@ /* 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, 2013 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 @@ -22,8 +22,8 @@ #include #include #include -#include #include +#include #include #include @@ -35,6 +35,7 @@ #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" @@ -47,7 +48,6 @@ #include "output/table-item.h" #include "output/text-item.h" -#include "gl/error.h" #include "gl/minmax.h" #include "gl/xalloc.h" @@ -119,22 +119,16 @@ static const ucs4_t unicode_box_chars[N_BOX] = 0x2564, 0x256a, 0x256c, 0x2564, 0x256a, 0x256c, 0x2554, 0x2560, 0x2560, + 0x2560, 0x256c, 0x256c, 0x2566, 0x256c, 0x256c, }; static inline int make_box_index (int left, int right, int top, int bottom) { - return ((right * 3 + bottom) * 3 + left) * 3 + top; + return ((right * RENDER_N_LINES + bottom) * RENDER_N_LINES + left) * RENDER_N_LINES + 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 { @@ -156,6 +150,11 @@ struct ascii_driver enum emphasis_style emphasis; /* How to emphasize text. */ char *chart_file_name; /* Name of files used for charts. */ + /* Colours for charts */ + struct xr_color fg; + struct xr_color bg; + + int width; /* Page width. */ int length; /* Page length minus margins and header. */ bool auto_width; /* Use viewwidth as page width? */ @@ -174,7 +173,7 @@ struct ascii_driver 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; @@ -202,6 +201,20 @@ static void ascii_draw_cell (void *, const struct table_cell *, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]); +static void +reallocate_lines (struct ascii_driver *a) +{ + if (a->length > a->allocated_lines) + { + int i; + a->lines = xnrealloc (a->lines, a->length, sizeof *a->lines); + for (i = a->allocated_lines; i < a->length; i++) + u8_line_init (&a->lines[i]); + a->allocated_lines = a->length; + } +} + + static struct ascii_driver * ascii_driver_cast (struct output_driver *driver) { @@ -249,6 +262,9 @@ ascii_create (const char *file_name, enum settings_output_devices device_type, a->auto_length = paper_length < 0; a->length = paper_length - vertical_margins (a); + parse_color (d, o, "background-color", "#FFFFFFFFFFFF", &a->bg); + parse_color (d, o, "foreground-color", "#000000000000", &a->fg); + box = parse_enum (opt (d, o, "box", "ascii"), "ascii", BOX_ASCII, "unicode", BOX_UNICODE, @@ -295,7 +311,7 @@ parse_page_size (struct driver_option *option) if (dim >= 1 && errno != ERANGE && *tail == '\0') dim = value; else - error (0, 0, _("%s: %s must be positive integer or `auto'"), + msg (MW, _("%s: %s must be positive integer or `auto'"), option->driver_name, option->name); } } @@ -327,7 +343,7 @@ update_page_size (struct ascii_driver *a, bool issue_error) if (a->width < MIN_WIDTH || a->length < MIN_LENGTH) { if (issue_error) - error (0, 0, + msg (ME, _("ascii: page excluding margins and headers " "must be at least %d characters wide by %d lines long, but " "as configured is only %d characters by %d lines"), @@ -340,6 +356,8 @@ update_page_size (struct ascii_driver *a, bool issue_error) return false; } + reallocate_lines (a); + return true; } @@ -360,7 +378,7 @@ ascii_destroy (struct output_driver *driver) 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); } @@ -374,8 +392,7 @@ ascii_flush (struct output_driver *driver) ascii_close_page (a); if (fn_close (a->file_name, a->file) != 0) - error (0, errno, _("ascii: closing output file `%s'"), - a->file_name); + msg_error (errno, _("ascii: closing output file `%s'"), a->file_name); a->file = NULL; } } @@ -511,7 +528,9 @@ ascii_submit (struct output_driver *driver, char *file_name; file_name = xr_draw_png_chart (chart_item, a->chart_file_name, - a->chart_cnt++); + a->chart_cnt++, + &a->fg, + &a->bg); if (file_name != NULL) { struct text_item *text_item; @@ -573,9 +592,9 @@ ascii_submit (struct output_driver *driver, } const struct output_driver_factory txt_driver_factory = - { "txt", ascii_create }; + { "txt", "-", ascii_create }; const struct output_driver_factory list_driver_factory = - { "list", ascii_create }; + { "list", "-", ascii_create }; static const struct output_driver_class ascii_driver_class = { @@ -678,136 +697,11 @@ ascii_draw_cell (void *a_, const struct table_cell *cell, 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 @@ -955,7 +849,6 @@ ascii_layout_cell (struct ascii_driver *a, const struct table_cell *cell, if (length == 0) return; - text = cell->contents; breaks = xmalloc (length + 1); u8_possible_linebreaks (CHAR_CAST (const uint8_t *, text), length, "UTF-8", breaks); @@ -973,6 +866,7 @@ ascii_layout_cell (struct ascii_driver *a, const struct table_cell *cell, size_t last_break_ofs = 0; int last_break_width = 0; int width = 0; + size_t graph_ofs; size_t ofs; for (ofs = 0; ofs < n; ) @@ -1008,25 +902,27 @@ ascii_layout_cell (struct ascii_driver *a, const struct table_cell *cell, } ofs += mblen; } - if (b[ofs] != UC_BREAK_MANDATORY) - { - while (ofs > 0 && isspace (line[ofs - 1])) - { - ofs--; - width--; - } - } - if (width > *widthp) - *widthp = width; + + /* Trim any trailing spaces off the end of the text to be drawn. */ + for (graph_ofs = ofs; graph_ofs > 0; graph_ofs--) + if (!isspace (line[graph_ofs - 1])) + break; + width -= ofs - graph_ofs; /* Draw text. */ - text_draw (a, cell->options, bb, clip, y, line, ofs, width); + text_draw (a, cell->options, bb, clip, y, line, graph_ofs, width); - /* Next line. */ - pos += ofs; - if (ofs < n && isspace (line[ofs])) - pos++; + /* If a new-line ended the line, just skip the new-line. Otherwise, skip + past any spaces past the end of the line (but not past a new-line). */ + if (b[ofs] == UC_BREAK_MANDATORY) + ofs++; + else + while (ofs < n && isspace (line[ofs]) && b[ofs] != UC_BREAK_MANDATORY) + ofs++; + if (width > *widthp) + *widthp = width; + pos += ofs; } *heightp = y - bb[V][0]; @@ -1059,6 +955,19 @@ ascii_test_write (struct output_driver *driver, 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); +} /* ascii_close_page () and support routines. */ @@ -1085,23 +994,23 @@ ascii_open_page (struct ascii_driver *a) a->file = fn_open (a->file_name, a->append ? "a" : "w"); if (a->file != NULL) { -#if HAVE_DECL_SIGWINCH if ( isatty (fileno (a->file))) { +#if HAVE_DECL_SIGWINCH struct sigaction action; sigemptyset (&action.sa_mask); action.sa_flags = 0; action.sa_handler = winch_handler; the_driver = a; + sigaction (SIGWINCH, &action, NULL); +#endif a->auto_width = true; a->auto_length = true; - sigaction (SIGWINCH, &action, NULL); } -#endif } else { - error (0, errno, _("ascii: opening output file `%s'"), + msg_error (errno, _("ascii: opening output file `%s'"), a->file_name); a->error = true; return false; @@ -1110,24 +1019,10 @@ ascii_open_page (struct ascii_driver *a) a->page_number++; - if (a->length > a->allocated_lines) - { - 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; - } - a->allocated_lines = a->length; - } + 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; } @@ -1186,7 +1081,7 @@ ascii_close_page (struct ascii_driver *a) 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;