X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fascii.c;h=78626cf13ff45912d7d0c5b689fefc1ba35a512f;hb=0755b9a4256554906377f2db62e25ac09255a790;hp=93e79e2e492499b2e4cc48e11c2e781399c58d04;hpb=14b360304396965ef0ed26f639e5b07e2766d23e;p=pspp diff --git a/src/output/ascii.c b/src/output/ascii.c index 93e79e2e49..78626cf13f 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" @@ -119,22 +120,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 { @@ -174,7 +169,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 +197,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) { @@ -340,6 +349,8 @@ update_page_size (struct ascii_driver *a, bool issue_error) return false; } + reallocate_lines (a); + return true; } @@ -360,7 +371,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); } @@ -543,6 +554,7 @@ ascii_submit (struct output_driver *driver, a->subtitle = xstrdup (text); break; + case TEXT_ITEM_COMMAND_OPEN: case TEXT_ITEM_COMMAND_CLOSE: break; @@ -572,9 +584,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 = { @@ -677,134 +689,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 = &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); - } + assert (y < a->allocated_lines); + return u8_line_reserve (&a->lines[y], x0, x1, n); } static void @@ -952,7 +841,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); @@ -970,6 +858,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; ) @@ -1005,25 +894,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]; @@ -1056,6 +947,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. */ @@ -1082,19 +986,19 @@ 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 { @@ -1107,24 +1011,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; } @@ -1183,7 +1073,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;