X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fascii.c;h=4a30663fa452df1fa9ef46e24708e87940a71fd7;hb=35abdb30d26f0bfb972c1712ee887a0f0fff6b97;hp=06addff506fe6e447548695f20410f2e41341f6e;hpb=73d0e3cb5a4e99b5d46ea0ca2af5e8cdbaf445bc;p=pspp-builds.git diff --git a/src/ascii.c b/src/ascii.c index 06addff5..4a30663f 100644 --- a/src/ascii.c +++ b/src/ascii.c @@ -18,7 +18,7 @@ 02111-1307, USA. */ #include -#include +#include "error.h" #include #include #include @@ -49,6 +49,7 @@ width=130 lpi=6 Only used to determine font size. cpi=10 + squeeze=off|on Squeeze multiple newlines into exactly one. left-margin=0 right-margin=0 @@ -140,6 +141,14 @@ enum FSTY_COUNT = 6 /* Number of font styles. */ }; +/* A line of text. */ +struct line + { + unsigned short *chars; /* Characters and attributes. */ + int char_cnt; /* Length. */ + int char_cap; /* Allocated bytes. */ + }; + /* ASCII output driver extension record. */ struct ascii_driver_ext { @@ -161,43 +170,48 @@ struct ascii_driver_ext struct len_string fonts[FSTY_COUNT]; /* Font styles; NULL=overstrike. */ int overstrike_style; /* OVS_SINGLE or OVS_LINE. */ int carriage_return_style; /* Carriage return style. */ + int squeeze_blank_lines; /* 1=squeeze multiple blank lines into one. */ /* Internal state. */ struct file_ext file; /* Output file. */ int page_number; /* Current page number. */ - unsigned short *page; /* Page content. */ - int page_size; /* Number of bytes allocated for page, attr. */ - int *line_len; /* Length of each line in page, attr. */ - int line_len_size; /* Number of ints allocated for line_len. */ + struct line *lines; /* Page content. */ + int lines_cap; /* Number of lines allocated. */ int w, l; /* Actual width & length w/o margins, etc. */ - int n_output; /* Number of lines output so far. */ int cur_font; /* Current font by OUTP_F_*. */ #if GLOBAL_DEBUGGING int debug; /* Set by som_text_draw(). */ #endif }; -static struct pool *ascii_pool; - static int postopen (struct file_ext *); static int preclose (struct file_ext *); -int -ascii_open_global (struct outp_class *this unused) +static struct outp_option_info *option_info; + +static int +ascii_open_global (struct outp_class *this UNUSED) { - ascii_pool = pool_create (); + option_info = xmalloc ( sizeof (struct outp_option_info ) ) ; + option_info->initial = 0; + option_info->options = 0; return 1; } -int -ascii_close_global (struct outp_class *this unused) + +static unsigned char *s=0; +static int +ascii_close_global (struct outp_class *this UNUSED) { - pool_destroy (ascii_pool); + free(option_info->initial); + free(option_info->options); + free(option_info); + free(s); return 1; } -int * -ascii_font_sizes (struct outp_class *this unused, int *n_valid_sizes) +static int * +ascii_font_sizes (struct outp_class *this UNUSED, int *n_valid_sizes) { static int valid_sizes[] = {12, 12, 0, 0}; @@ -206,7 +220,7 @@ ascii_font_sizes (struct outp_class *this unused, int *n_valid_sizes) return valid_sizes; } -int +static int ascii_preopen_driver (struct outp_driver *this) { struct ascii_driver_ext *x; @@ -235,6 +249,7 @@ ascii_preopen_driver (struct outp_driver *this) ls_null (&x->fonts[i]); x->overstrike_style = OVS_SINGLE; x->carriage_return_style = CRS_BS; + x->squeeze_blank_lines = 0; x->file.filename = NULL; x->file.mode = "wb"; x->file.file = NULL; @@ -243,11 +258,8 @@ ascii_preopen_driver (struct outp_driver *this) x->file.postopen = postopen; x->file.preclose = preclose; x->page_number = 0; - x->page = NULL; - x->page_size = 0; - x->line_len = NULL; - x->line_len_size = 0; - x->n_output = 0; + x->lines = NULL; + x->lines_cap = 0; x->cur_font = OUTP_F_R; #if GLOBAL_DEBUGGING x->debug = 0; @@ -255,7 +267,7 @@ ascii_preopen_driver (struct outp_driver *this) return 1; } -int +static int ascii_postopen_driver (struct outp_driver *this) { struct ascii_driver_ext *x = this->ext; @@ -283,11 +295,11 @@ ascii_postopen_driver (struct outp_driver *this) this->length = x->l * this->vert; if (ls_null_p (&x->ops[OPS_FORMFEED])) - ls_create (ascii_pool, &x->ops[OPS_FORMFEED], "\f"); + ls_create (&x->ops[OPS_FORMFEED], "\f"); if (ls_null_p (&x->ops[OPS_NEWLINE]) - || !strcmp (ls_value (&x->ops[OPS_NEWLINE]), "default")) + || !strcmp (ls_c_str (&x->ops[OPS_NEWLINE]), "default")) { - ls_create (ascii_pool, &x->ops[OPS_NEWLINE], "\n"); + ls_create (&x->ops[OPS_NEWLINE], "\n"); x->file.mode = "wt"; } @@ -346,7 +358,7 @@ ascii_postopen_driver (struct outp_driver *this) c[0] = '+'; break; } - ls_create (ascii_pool, &x->box[i], c); + ls_create (&x->box[i], c); } } @@ -380,17 +392,30 @@ ascii_postopen_driver (struct outp_driver *this) return 1; } -int +static int ascii_close_driver (struct outp_driver *this) { struct ascii_driver_ext *x = this->ext; + int i; assert (this->driver_open == 1); msg (VM (2), _("%s: Beginning closing..."), this->name); x = this->ext; - free (x->page); - free (x->line_len); + for (i = 0; i < OPS_COUNT; i++) + ls_destroy (&x->ops[i]); + for (i = 0; i < LNS_COUNT; i++) + ls_destroy (&x->box[i]); + for (i = 0; i < FSTY_COUNT; i++) + ls_destroy (&x->fonts[i]); + if (x->lines != NULL) + { + int line; + + for (line = 0; line < x->lines_cap; line++) + free (x->lines[line].chars); + free (x->lines); + } fn_close_ext (&x->file); free (x->file.filename); free (x); @@ -438,11 +463,11 @@ static struct outp_option option_tab[] = {"overstrike-style", 3, 0}, {"tab-width", nonneg_int_arg, 4}, {"carriage-return-style", 4, 0}, + {"squeeze", boolean_arg, 2}, {"", 0, 0}, }; -static struct outp_option_info option_info; -void +static void ascii_option (struct outp_driver *this, const char *key, const struct string *val) { @@ -450,7 +475,7 @@ ascii_option (struct outp_driver *this, const char *key, int cat, subcat; const char *value; - value = ds_value (val); + value = ds_c_str (val); if (!strncmp (key, "box[", 4)) { char *tail; @@ -464,11 +489,11 @@ ascii_option (struct outp_driver *this, const char *key, } if (!ls_null_p (&x->box[indx])) msg (SW, _("Duplicate value for key `%s'."), key); - ls_create (ascii_pool, &x->box[indx], value); + ls_create (&x->box[indx], value); return; } - cat = outp_match_keyword (key, option_tab, &option_info, &subcat); + cat = outp_match_keyword (key, option_tab, option_info, &subcat); switch (cat) { case 0: @@ -591,18 +616,19 @@ ascii_option (struct outp_driver *this, const char *key, break; default: assert (0); + abort (); } - ls_create (ascii_pool, s, value); + ls_create (s, value); } break; case font_string_arg: { if (!strcmp (value, "overstrike")) { - ls_destroy (ascii_pool, &x->fonts[subcat]); + ls_destroy (&x->fonts[subcat]); return; } - ls_create (ascii_pool, &x->fonts[subcat], value); + ls_create (&x->fonts[subcat], value); } break; case boolean_arg: @@ -622,11 +648,14 @@ ascii_option (struct outp_driver *this, const char *key, switch (subcat) { case 0: - x->headers = 0; + x->headers = setting; break; case 1: x->paginate = setting; break; + case 2: + x->squeeze_blank_lines = setting; + break; default: assert (0); } @@ -643,7 +672,7 @@ postopen (struct file_ext *f) struct ascii_driver_ext *x = f->param; struct len_string *s = &x->ops[OPS_INIT]; - if (!ls_empty_p (s) && fwrite (ls_value (s), ls_length (s), 1, f->file) < 1) + if (!ls_empty_p (s) && fwrite (ls_c_str (s), ls_length (s), 1, f->file) < 1) { msg (ME, _("ASCII output driver: %s: %s"), f->filename, strerror (errno)); @@ -658,7 +687,7 @@ preclose (struct file_ext *f) struct ascii_driver_ext *x = f->param; struct len_string *d = &x->ops[OPS_DONE]; - if (!ls_empty_p (d) && fwrite (ls_value (d), ls_length (d), 1, f->file) < 1) + if (!ls_empty_p (d) && fwrite (ls_c_str (d), ls_length (d), 1, f->file) < 1) { msg (ME, _("ASCII output driver: %s: %s"), f->filename, strerror (errno)); @@ -667,11 +696,11 @@ preclose (struct file_ext *f) return 1; } -int +static int ascii_open_page (struct outp_driver *this) { struct ascii_driver_ext *x = this->ext; - int req_page_size; + int i; assert (this->driver_open && !this->page_open); x->page_number++; @@ -682,21 +711,20 @@ ascii_open_page (struct outp_driver *this) return 0; } - req_page_size = x->w * x->l; - if (req_page_size > x->page_size || req_page_size / 2 < x->page_size) - { - x->page_size = req_page_size; - x->page = xrealloc (x->page, sizeof *x->page * req_page_size); - } - - if (x->l > x->line_len_size) + if (x->l > x->lines_cap) { - x->line_len_size = x->l; - x->line_len = xrealloc (x->line_len, - sizeof *x->line_len * x->line_len_size); + x->lines = xrealloc (x->lines, sizeof *x->lines * x->l); + for (i = x->lines_cap; i < x->l; i++) + { + struct line *line = &x->lines[i]; + line->chars = NULL; + line->char_cap = 0; + } + x->lines_cap = x->l; } - memset (x->line_len, 0, sizeof *x->line_len * x->l); + for (i = 0; i < x->l; i++) + x->lines[i].char_cnt = 0; this->page_open = 1; return 1; @@ -707,18 +735,26 @@ ascii_open_page (struct outp_driver *this) static inline void expand_line (struct ascii_driver_ext *x, int i, int l) { - int limit = i * x->w + l; + struct line *line; int j; - for (j = i * x->w + x->line_len[i]; j < limit; j++) - x->page[j] = ' '; - x->line_len[i] = l; + assert (i < x->lines_cap); + line = &x->lines[i]; + if (l > line->char_cap) + { + line->char_cap = l * 2; + line->chars = xrealloc (line->chars, + line->char_cap * sizeof *line->chars); + } + for (j = line->char_cnt; j < l; j++) + line->chars[j] = ' '; + line->char_cnt = l; } /* Puts line L at (H,K) in the current output page. Assumes struct ascii_driver_ext named `ext'. */ #define draw_line(H, K, L) \ - ext->page[ext->w * (K) + (H)] = (L) | 0x800 + ext->lines[K].chars[H] = (L) | 0x800 /* Line styles for each position. */ #define T(STYLE) (STYLE<ext; int x1 = r->x1 / this->horiz; @@ -753,16 +789,16 @@ ascii_line_horz (struct outp_driver *this, const struct rect *r, } #endif - if (ext->line_len[y1] < x2) + if (ext->lines[y1].char_cnt < x2) expand_line (ext, y1, x2); for (x = x1; x < x2; x++) draw_line (x, y1, (style << LNS_LEFT) | (style << LNS_RIGHT)); } -void +static void ascii_line_vert (struct outp_driver *this, const struct rect *r, - const struct color *c unused, int style) + const struct color *c UNUSED, int style) { struct ascii_driver_ext *ext = this->ext; int x1 = r->x1 / this->horiz; @@ -788,16 +824,16 @@ ascii_line_vert (struct outp_driver *this, const struct rect *r, #endif for (y = y1; y < y2; y++) - if (ext->line_len[y] <= x1) + if (ext->lines[y].char_cnt <= x1) expand_line (ext, y, x1 + 1); for (y = y1; y < y2; y++) draw_line (x1, y, (style << LNS_TOP) | (style << LNS_BOTTOM)); } -void +static void ascii_line_intersection (struct outp_driver *this, const struct rect *r, - const struct color *c unused, + const struct color *c UNUSED, const struct outp_styles *style) { struct ascii_driver_ext *ext = this->ext; @@ -820,52 +856,38 @@ ascii_line_intersection (struct outp_driver *this, const struct rect *r, l = ((style->l << LNS_LEFT) | (style->r << LNS_RIGHT) | (style->t << LNS_TOP) | (style->b << LNS_BOTTOM)); - if (ext->line_len[y] <= x) + if (ext->lines[y].char_cnt <= x) expand_line (ext, y, x + 1); draw_line (x, y, l); } -void -ascii_line_width (struct outp_driver *this, int *width, int *height) -{ - int i; - - assert (this->driver_open && this->page_open); - width[0] = height[0] = 0; - for (i = 1; i < OUTP_L_COUNT; i++) - { - width[i] = this->horiz; - height[i] = this->vert; - } -} - /* FIXME: Later we could set this up so that for certain devices it performs shading? */ -void -ascii_box (struct outp_driver *this unused, const struct rect *r unused, - const struct color *bord unused, const struct color *fill unused) +static void +ascii_box (struct outp_driver *this UNUSED, const struct rect *r UNUSED, + const struct color *bord UNUSED, const struct color *fill UNUSED) { assert (this->driver_open && this->page_open); } /* Polylines not supported. */ -void -ascii_polyline_begin (struct outp_driver *this unused, const struct color *c unused) +static void +ascii_polyline_begin (struct outp_driver *this UNUSED, const struct color *c UNUSED) { assert (this->driver_open && this->page_open); } -void -ascii_polyline_point (struct outp_driver *this unused, int x unused, int y unused) +static void +ascii_polyline_point (struct outp_driver *this UNUSED, int x UNUSED, int y UNUSED) { assert (this->driver_open && this->page_open); } -void -ascii_polyline_end (struct outp_driver *this unused) +static void +ascii_polyline_end (struct outp_driver *this UNUSED) { assert (this->driver_open && this->page_open); } -void +static void ascii_text_set_font_by_name (struct outp_driver * this, const char *s) { struct ascii_driver_ext *x = this->ext; @@ -886,7 +908,7 @@ ascii_text_set_font_by_name (struct outp_driver * this, const char *s) x->cur_font = OUTP_F_B; } -void +static void ascii_text_set_font_by_position (struct outp_driver *this, int pos) { struct ascii_driver_ext *x = this->ext; @@ -894,13 +916,13 @@ ascii_text_set_font_by_position (struct outp_driver *this, int pos) x->cur_font = pos >= 0 && pos < 4 ? pos : 0; } -void -ascii_text_set_font_by_family (struct outp_driver *this unused, const char *s unused) +static void +ascii_text_set_font_by_family (struct outp_driver *this UNUSED, const char *s UNUSED) { assert (this->driver_open && this->page_open); } -const char * +static const char * ascii_text_get_font_name (struct outp_driver *this) { struct ascii_driver_ext *x = this->ext; @@ -922,21 +944,21 @@ ascii_text_get_font_name (struct outp_driver *this) abort (); } -const char * -ascii_text_get_font_family (struct outp_driver *this unused) +static const char * +ascii_text_get_font_family (struct outp_driver *this UNUSED) { assert (this->driver_open && this->page_open); return ""; } -int +static int ascii_text_set_size (struct outp_driver *this, int size) { assert (this->driver_open && this->page_open); return size == this->vert; } -int +static int ascii_text_get_size (struct outp_driver *this, int *em_width) { assert (this->driver_open && this->page_open); @@ -962,7 +984,7 @@ delineate (struct outp_driver *this, struct outp_text *t, int draw) int max_y; /* Current position in string, character following end of string. */ - const char *s = ls_value (&t->s); + const char *s = ls_c_str (&t->s); const char *end = ls_end (&t->s); /* Temporary struct outp_text to pass to low-level function. */ @@ -1050,7 +1072,7 @@ delineate (struct outp_driver *this, struct outp_text *t, int draw) t->v = (temp.y * this->vert) - t->y; } -void +static void ascii_text_metrics (struct outp_driver *this, struct outp_text *t) { assert (this->driver_open && this->page_open); @@ -1063,7 +1085,7 @@ ascii_text_metrics (struct outp_driver *this, struct outp_text *t) delineate (this, t, 0); } -void +static void ascii_text_draw (struct outp_driver *this, struct outp_text *t) { /* FIXME: orientations not supported. */ @@ -1092,9 +1114,9 @@ text_draw (struct outp_driver *this, struct outp_text *t) unsigned attr = ext->cur_font << 8; int x = t->x; - int y = t->y * ext->w; + int y = t->y; - char *s = ls_value (&t->s); + char *s = ls_c_str (&t->s); /* Expand the line with the assumption that S takes up LEN character spaces (sometimes it takes up less). */ @@ -1117,7 +1139,7 @@ text_draw (struct outp_driver *this, struct outp_text *t) if (!(t->y < ext->l && x < ext->w)) return; min_len = min (x + ls_length (&t->s), ext->w); - if (ext->line_len[t->y] < min_len) + if (ext->lines[t->y].char_cnt < min_len) expand_line (ext, t->y, min_len); { @@ -1126,7 +1148,7 @@ text_draw (struct outp_driver *this, struct outp_text *t) if (len + x > ext->w) len = ext->w - x; while (len--) - ext->page[y + x++] = *s++ | attr; + ext->lines[y].chars[x++] = *s++ | attr; } } @@ -1192,7 +1214,7 @@ output_shorts (struct outp_driver *this, if (remaining >= len) { - memcpy (line_p, ls_value (box), len); + memcpy (line_p, ls_c_str (box), len); line_p += len; remaining -= len; } @@ -1200,7 +1222,7 @@ output_shorts (struct outp_driver *this, { if (!commit_line_buf (this)) return 0; - output_string (this, ls_value (box), ls_end (box)); + output_string (this, ls_c_str (box), ls_end (box)); remaining = LINE_BUF_SIZE - (line_p - line_buf); } } @@ -1223,6 +1245,7 @@ output_shorts (struct outp_driver *this, break; default: assert (0); + abort (); } if (!on) { @@ -1251,6 +1274,7 @@ output_shorts (struct outp_driver *this, break; default: assert (0); + abort (); } else { @@ -1337,6 +1361,7 @@ return_carriage (struct outp_driver *this, int n_chars) break; default: assert (0); + abort (); } } @@ -1346,9 +1371,8 @@ static void output_lines (struct outp_driver *this, int first, int count) { struct ascii_driver_ext *ext = this->ext; + int line_num; - unsigned short *p = &ext->page[ext->w * first]; - int *len = &ext->line_len[first]; struct len_string *newline = &ext->ops[OPS_NEWLINE]; int n_chars; @@ -1357,15 +1381,25 @@ output_lines (struct outp_driver *this, int first, int count) if (NULL == ext->file.file) return; - while (count--) /* Iterate over all the lines to be output. */ + /* Iterate over all the lines to be output. */ + for (line_num = first; line_num < first + count; line_num++) { - unsigned short *end_p; + struct line *line = &ext->lines[line_num]; + unsigned short *p = line->chars; + unsigned short *end_p = p + line->char_cnt; unsigned short *bp, *ep; unsigned short attr = 0; - end_p = p + *len++; assert (end_p >= p); + /* Squeeze multiple blank lines into a single blank line if + requested. */ + if (ext->squeeze_blank_lines + && line_num > first + && ext->lines[line_num].char_cnt == 0 + && ext->lines[line_num - 1].char_cnt == 0) + continue; + /* Output every character in the line in the appropriate manner. */ n_passes = 1; @@ -1402,9 +1436,10 @@ output_lines (struct outp_driver *this, int first, int count) break; default: assert (0); + abort (); } if (off) - output_string (this, ls_value (off), ls_end (off)); + output_string (this, ls_c_str (off), ls_end (off)); } /* Turn on new font. */ @@ -1426,9 +1461,10 @@ output_lines (struct outp_driver *this, int first, int count) break; default: assert (0); + abort (); } if (on) - output_string (this, ls_value (on), ls_end (on)); + output_string (this, ls_c_str (on), ls_end (on)); } ep = bp + 1; @@ -1460,6 +1496,9 @@ output_lines (struct outp_driver *this, int first, int count) ch = *ep; n_passes = 3; break; + default: + assert (0); + abort (); } output_char (this, 1, ch); n_chars += ep - bp + 1; @@ -1483,16 +1522,15 @@ output_lines (struct outp_driver *this, int first, int count) ep = bp; } } - p += ext->w; - output_string (this, ls_value (newline), ls_end (newline)); + output_string (this, ls_c_str (newline), ls_end (newline)); } } -int + +static int ascii_close_page (struct outp_driver *this) { - static unsigned char *s; static int s_len; struct ascii_driver_ext *x = this->ext; @@ -1517,7 +1555,7 @@ ascii_close_page (struct outp_driver *this) } for (cp = s, i = 0; i < x->top_margin; i++) { - memcpy (cp, ls_value (&x->ops[OPS_NEWLINE]), nl_len); + memcpy (cp, ls_c_str (&x->ops[OPS_NEWLINE]), nl_len); cp += nl_len; } output_string (this, s, &s[total_len]); @@ -1547,7 +1585,7 @@ ascii_close_page (struct outp_driver *this) len = min ((int) strlen (outp_title), x->w); memcpy (s, outp_title, len); } - memcpy (&s[x->w], ls_value (&x->ops[OPS_NEWLINE]), nl_len); + memcpy (&s[x->w], ls_c_str (&x->ops[OPS_NEWLINE]), nl_len); output_string (this, s, &s[total_len]); memset (s, ' ', x->w); @@ -1560,14 +1598,14 @@ ascii_close_page (struct outp_driver *this) len = min ((int) strlen (string), x->w); memcpy (s, string, len); } - memcpy (&s[x->w], ls_value (&x->ops[OPS_NEWLINE]), nl_len); + memcpy (&s[x->w], ls_c_str (&x->ops[OPS_NEWLINE]), nl_len); output_string (this, s, &s[total_len]); output_string (this, &s[x->w], &s[total_len]); } if (line_p != line_buf && !commit_line_buf (this)) return 0; - output_lines (this, x->n_output, x->l - x->n_output); + output_lines (this, 0, x->l); ff_len = ls_length (&x->ops[OPS_FORMFEED]); total_len = x->bottom_margin * nl_len + ff_len; @@ -1575,17 +1613,20 @@ ascii_close_page (struct outp_driver *this) s = xrealloc (s, total_len); for (cp = s, i = 0; i < x->bottom_margin; i++) { - memcpy (cp, ls_value (&x->ops[OPS_NEWLINE]), nl_len); + memcpy (cp, ls_c_str (&x->ops[OPS_NEWLINE]), nl_len); cp += nl_len; } - memcpy (cp, ls_value (&x->ops[OPS_FORMFEED]), ff_len); + memcpy (cp, ls_c_str (&x->ops[OPS_FORMFEED]), ff_len); if ( x->paginate ) output_string (this, s, &s[total_len]); + if (line_p != line_buf && !commit_line_buf (this)) + { + free(s); + s=0; return 0; + } - x->n_output = 0; - this->page_open = 0; return 1; }