X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fpostscript.c;h=fd738ababba65e1e344a053d53466f1722eb0b6c;hb=3417680e253b1bfc4519347ef06536378026be2a;hp=9fa1615246b6558e700d94a21441330c062a93ba;hpb=440ac00aa72410d1c0e41633bd651c4c54871f87;p=pspp diff --git a/src/postscript.c b/src/postscript.c index 9fa1615246..fd738ababb 100644 --- a/src/postscript.c +++ b/src/postscript.c @@ -14,64 +14,43 @@ 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ -/* AIX requires this to be the first thing in the file. */ #include -#if __GNUC__ -#define alloca __builtin_alloca -#else -#if HAVE_ALLOCA_H -#include -#else -#ifdef _AIX -#pragma alloca -#else -#ifndef alloca /* predefined by HP cc +Olibcalls */ -char *alloca (); -#endif -#endif -#endif -#endif /*this #if encloses the remainder of the file. */ #if !NO_POSTSCRIPT #include -#include +#include "error.h" #include #include #include +#include #if HAVE_UNISTD_H #include #endif -#if TIME_WITH_SYS_TIME -#include -#include -#else -#if HAVE_SYS_TIME_H -#include -#else -#include -#endif -#endif - #include "alloc.h" #include "bitvector.h" #include "error.h" #include "filename.h" #include "font.h" +#include "getl.h" #include "getline.h" #include "hash.h" #include "main.h" #include "misc.h" #include "misc.h" #include "output.h" +#include "som.h" #include "version.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + /* FIXMEs: optimize-text-size not implemented. @@ -283,6 +262,7 @@ static unsigned hash_font_entry (const void *, void *param); static void free_font_entry (void *, void *foo); static struct font_entry *load_font (struct outp_driver *, const char *dit); static void init_fonts (void); +static void done_fonts (void); static void dump_lines (struct outp_driver *this); @@ -302,22 +282,24 @@ static char *quote_ps_string (char *dest, const char *string); /* Driver initialization. */ -int -ps_open_global (struct outp_class *this unused) +static int +ps_open_global (struct outp_class *this UNUSED) { init_fonts (); groff_init (); return 1; } -int -ps_close_global (struct outp_class *this unused) +static int +ps_close_global (struct outp_class *this UNUSED) { + groff_done (); + done_fonts (); return 1; } -int * -ps_font_sizes (struct outp_class *this unused, int *n_valid_sizes) +static int * +ps_font_sizes (struct outp_class *this UNUSED, int *n_valid_sizes) { /* Allow fonts up to 1" in height. */ static int valid_sizes[] = @@ -328,7 +310,7 @@ ps_font_sizes (struct outp_class *this unused, int *n_valid_sizes) return valid_sizes; } -int +static int ps_preopen_driver (struct outp_driver *this) { struct ps_driver_ext *x; @@ -403,7 +385,7 @@ ps_preopen_driver (struct outp_driver *this) return 1; } -int +static int ps_postopen_driver (struct outp_driver *this) { struct ps_driver_ext *x = this->ext; @@ -476,7 +458,7 @@ ps_postopen_driver (struct outp_driver *this) return 1; } -int +static int ps_close_driver (struct outp_driver *this) { struct ps_driver_ext *x = this->ext; @@ -510,14 +492,14 @@ ps_close_driver (struct outp_driver *this) /* font_entry comparison function for hash tables. */ static int -compare_font_entry (const void *a, const void *b, void *foobar unused) +compare_font_entry (const void *a, const void *b, void *foobar UNUSED) { return strcmp (((struct font_entry *) a)->dit, ((struct font_entry *) b)->dit); } /* font_entry hash function for hash tables. */ static unsigned -hash_font_entry (const void *fe_, void *foobar unused) +hash_font_entry (const void *fe_, void *foobar UNUSED) { const struct font_entry *fe = fe_; return hsh_hash_string (fe->dit); @@ -525,7 +507,7 @@ hash_font_entry (const void *fe_, void *foobar unused) /* font_entry destructor function for hash tables. */ static void -free_font_entry (void *pa, void *foo unused) +free_font_entry (void *pa, void *foo UNUSED) { struct font_entry *a = pa; free (a->dit); @@ -578,12 +560,12 @@ static struct outp_option option_tab[] = }; static struct outp_option_info option_info; -void +static void ps_option (struct outp_driver *this, const char *key, const struct string *val) { struct ps_driver_ext *x = this->ext; int cat, subcat; - char *value = ds_value (val); + char *value = ds_c_str (val); cat = outp_match_keyword (key, option_tab, &option_info, &subcat); @@ -677,6 +659,7 @@ ps_option (struct outp_driver *this, const char *key, const struct string *val) break; default: assert (0); + abort (); } if (setting) x->output_options |= mask; @@ -778,6 +761,7 @@ ps_option (struct outp_driver *this, const char *key, const struct string *val) break; default: assert (0); + abort (); } if (*dest) free (*dest); @@ -872,7 +856,7 @@ find_ps_file (struct outp_driver *this, const char *name) /* Hash table comparison function for ps_encoding's. */ static int -compare_ps_encoding (const void *pa, const void *pb, void *foo unused) +compare_ps_encoding (const void *pa, const void *pb, void *foo UNUSED) { const struct ps_encoding *a = pa; const struct ps_encoding *b = pb; @@ -882,7 +866,7 @@ compare_ps_encoding (const void *pa, const void *pb, void *foo unused) /* Hash table hash function for ps_encoding's. */ static unsigned -hash_ps_encoding (const void *pa, void *foo unused) +hash_ps_encoding (const void *pa, void *foo UNUSED) { const struct ps_encoding *a = pa; @@ -891,7 +875,7 @@ hash_ps_encoding (const void *pa, void *foo unused) /* Hash table free function for ps_encoding's. */ static void -free_ps_encoding (void *pa, void *foo unused) +free_ps_encoding (void *pa, void *foo UNUSED) { struct ps_encoding *a = pa; @@ -912,8 +896,8 @@ output_encodings (struct outp_driver *this) struct string line, buf; - ds_init (NULL, &line, 128); - ds_init (NULL, &buf, 128); + ds_init (&line, 128); + ds_init (&buf, 128); for (pe = hsh_first (x->encodings, &iter); pe != NULL; pe = hsh_next (x->encodings, &iter)) { @@ -960,7 +944,7 @@ output_encodings (struct outp_driver *this) if (buf.length == 0) continue; - pschar = strtok_r (ds_value (&buf), " \t\r\n", &sp); + pschar = strtok_r (ds_c_str (&buf), " \t\r\n", &sp); code = strtok_r (NULL, " \t\r\n", &sp); if (*pschar == 0 || *code == 0) continue; @@ -998,14 +982,14 @@ output_encodings (struct outp_driver *this) if (ds_length (&line) + strlen (temp) > 70) { - ds_concat (&line, x->eol); - fputs (ds_value (&line), x->file.file); + ds_puts (&line, x->eol); + fputs (ds_c_str (&line), x->file.file); ds_clear (&line); } - ds_concat (&line, temp); + ds_puts (&line, temp); } - ds_concat (&line, x->eol); - fputs (ds_value (&line), x->file.file); + ds_puts (&line, x->eol); + fputs (ds_c_str (&line), x->file.file); if (fclose (f) == EOF) msg (MW, _("PostScript driver: Error closing encoding file `%s'."), @@ -1067,14 +1051,13 @@ static void add_encoding (struct outp_driver *this, char *filename) { struct ps_driver_ext *x = this->ext; - struct ps_encoding **pe; filename = find_encoding_file (this, filename); if (!filename) return; - pe = (struct ps_encoding **) hsh_probe (x->encodings, (void *) &filename); + pe = (struct ps_encoding **) hsh_probe (x->encodings, &filename); if (*pe) { free (filename); @@ -1119,12 +1102,10 @@ read_ps_encodings (struct outp_driver *this) where.line_number = 0; err_push_file_locator (&where); - ds_init (NULL, &line, 128); + ds_init (&line, 128); for (;;) { - char *bp; - if (!ds_get_config_line (f, &line, &where)) { if (ferror (f)) @@ -1132,7 +1113,7 @@ read_ps_encodings (struct outp_driver *this) break; } - add_encoding (this, bp); + add_encoding (this, line.string); } ds_destroy (&line); @@ -1465,7 +1446,7 @@ postopen (struct file_ext *f) char *beg; beg = buf2 = fn_interp_vars (buf, ps_get_var); len = strlen (buf2); - while (isspace (*beg)) + while (isspace ((unsigned char) *beg)) beg++, len--; if (beg[len - 1] == '\n') len--; @@ -1507,7 +1488,7 @@ quote_ps_name (char *dest, const char *string) const char *sp; for (sp = string; *sp; sp++) - switch (*(unsigned char *) sp) + switch (*sp) { case 'a': case 'f': @@ -1582,7 +1563,7 @@ quote_ps_name (char *dest, const char *string) *dp++ = '<'; for (sp = string; *sp && dp < &dest[256]; sp++) { - sprintf (dp, "%02x", *(unsigned char *) sp); + sprintf (dp, "%02x", (unsigned char) *sp); dp += 2; } return stpcpy (dp, ">cvn"); @@ -1607,7 +1588,7 @@ quote_ps_string (char *dest, const char *string) dp = stpcpy (dp, "\\("); else if (*sp == ')') dp = stpcpy (dp, "\\)"); - else if (*sp < 32 || *((unsigned char *) sp) > 127) + else if (*sp < 32 || (unsigned char) *sp > 127) dp = spprintf (dp, "\\%3o", *sp); else *dp++ = *sp; @@ -1653,7 +1634,7 @@ preclose (struct file_ext *f) return 1; } -int +static int ps_open_page (struct outp_driver *this) { struct ps_driver_ext *x = this->ext; @@ -1707,10 +1688,12 @@ ps_open_page (struct outp_driver *this) draw_headers (this); } + this->cp_y = 0; + return !ferror (x->file.file); } -int +static int ps_close_page (struct outp_driver *this) { struct ps_driver_ext *x = this->ext; @@ -1728,26 +1711,45 @@ ps_close_page (struct outp_driver *this) this->page_open = 0; return !ferror (x->file.file); } + +static void +ps_submit (struct outp_driver *this UNUSED, struct som_entity *s) +{ + switch (s->type) + { + case SOM_CHART: + break; + default: + assert(0); + break; + } +} /* Lines. */ /* qsort() comparison function for int tuples. */ static int -int_2_compare (const void *a, const void *b) +int_2_compare (const void *a_, const void *b_) { - return *((const int *) a) - *((const int *) b); + const int *a = a_; + const int *b = b_; + + return *a < *b ? -1 : *a > *b; } /* Hash table comparison function for cached lines. */ static int -compare_line (const void *a, const void *b, void *foo unused) +compare_line (const void *a_, const void *b_, void *foo UNUSED) { - return ((struct line_form *) a)->ind - ((struct line_form *) b)->ind; + const struct line_form *a = a_; + const struct line_form *b = b_; + + return a->ind < b->ind ? -1 : a->ind > b->ind; } /* Hash table hash function for cached lines. */ static unsigned -hash_line (const void *pa, void *foo unused) +hash_line (const void *pa, void *foo UNUSED) { const struct line_form *a = pa; @@ -1756,7 +1758,7 @@ hash_line (const void *pa, void *foo unused) /* Hash table free function for cached lines. */ static void -free_line (void *pa, void *foo unused) +free_line (void *pa, void *foo UNUSED) { free (pa); } @@ -1886,8 +1888,7 @@ line (struct outp_driver *this, int type, int ind, int dep1, int dep2) if (ext->lines[type] == NULL) ext->lines[type] = hsh_create (31, compare_line, hash_line, free_line, NULL); - f = (struct line_form **) hsh_probe (ext->lines[type], - (struct line_form *) & ind); + f = (struct line_form **) hsh_probe (ext->lines[type], &ind); if (*f == NULL) { *f = xmalloc (sizeof **f + sizeof (int[15][2])); @@ -1908,9 +1909,9 @@ line (struct outp_driver *this, int type, int ind, int dep1, int dep2) (*f)->ndep++; } -void +static void ps_line_horz (struct outp_driver *this, const struct rect *r, - const struct color *c unused, int style) + const struct color *c UNUSED, int style) { /* Must match output.h:OUTP_L_*. */ static const int types[OUTP_L_COUNT] = @@ -1925,9 +1926,9 @@ ps_line_horz (struct outp_driver *this, const struct rect *r, line (this, style, y, r->x1, r->x2); } -void +static void ps_line_vert (struct outp_driver *this, const struct rect *r, - const struct color *c unused, int style) + const struct color *c UNUSED, int style) { /* Must match output.h:OUTP_L_*. */ static const int types[OUTP_L_COUNT] = @@ -1947,9 +1948,9 @@ ps_line_vert (struct outp_driver *this, const struct rect *r, #define T (style->t != OUTP_L_NONE) #define B (style->b != OUTP_L_NONE) -void +static void ps_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 ps_driver_ext *ext = this->ext; @@ -2029,39 +2030,26 @@ ps_line_intersection (struct outp_driver *this, const struct rect *r, } } -void -ps_line_width (struct outp_driver *this, int *width, int *height) -{ - struct ps_driver_ext *x = this->ext; - - assert (this->driver_open && this->page_open); - width[0] = height[0] = 0; - width[1] = height[1] = 2 * x->line_gutter + x->line_width; - width[2] = height[2] = (2 * x->line_gutter + 2 * x->line_width - + x->line_space); - width[3] = height[3] = 2 * x->line_gutter + x->line_width; -} - -void -ps_box (struct outp_driver *this unused, const struct rect *r unused, - const struct color *bord unused, const struct color *fill unused) +static void +ps_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); } -void -ps_polyline_begin (struct outp_driver *this unused, - const struct color *c unused) +static void +ps_polyline_begin (struct outp_driver *this UNUSED, + const struct color *c UNUSED) { assert (this->driver_open && this->page_open); } -void -ps_polyline_point (struct outp_driver *this unused, int x unused, int y unused) +static void +ps_polyline_point (struct outp_driver *this UNUSED, int x UNUSED, int y UNUSED) { assert (this->driver_open && this->page_open); } -void -ps_polyline_end (struct outp_driver *this unused) +static void +ps_polyline_end (struct outp_driver *this UNUSED) { assert (this->driver_open && this->page_open); } @@ -2157,7 +2145,7 @@ draw_headers (struct outp_driver *this) /* Text. */ -void +static void ps_text_set_font_by_name (struct outp_driver *this, const char *dit) { struct ps_driver_ext *x = this->ext; @@ -2186,7 +2174,7 @@ ps_text_set_font_by_name (struct outp_driver *this, const char *dit) x->current = fe; } -void +static void ps_text_set_font_by_position (struct outp_driver *this, int pos) { struct ps_driver_ext *x = this->ext; @@ -2233,7 +2221,7 @@ ps_text_set_font_by_position (struct outp_driver *this, int pos) local_free (dit); } -void +static void ps_text_set_font_family (struct outp_driver *this, const char *s) { struct ps_driver_ext *x = this->ext; @@ -2244,7 +2232,7 @@ ps_text_set_font_family (struct outp_driver *this, const char *s) x->family = xstrdup (s); } -const char * +static const char * ps_text_get_font_name (struct outp_driver *this) { struct ps_driver_ext *x = this->ext; @@ -2253,7 +2241,7 @@ ps_text_get_font_name (struct outp_driver *this) return x->current->font->name; } -const char * +static const char * ps_text_get_font_family (struct outp_driver *this) { struct ps_driver_ext *x = this->ext; @@ -2262,7 +2250,7 @@ ps_text_get_font_family (struct outp_driver *this) return x->family; } -int +static int ps_text_set_size (struct outp_driver *this, int size) { struct ps_driver_ext *x = this->ext; @@ -2272,7 +2260,7 @@ ps_text_set_size (struct outp_driver *this, int size) return 1; } -int +static int ps_text_get_size (struct outp_driver *this, int *em_width) { struct ps_driver_ext *x = this->ext; @@ -2295,7 +2283,7 @@ struct output_char /* Hash table comparison function for ps_combo structs. */ static int -compare_ps_combo (const void *pa, const void *pb, void *foo unused) +compare_ps_combo (const void *pa, const void *pb, void *foo UNUSED) { const struct ps_font_combo *a = pa; const struct ps_font_combo *b = pb; @@ -2305,7 +2293,7 @@ compare_ps_combo (const void *pa, const void *pb, void *foo unused) /* Hash table hash function for ps_combo structs. */ static unsigned -hash_ps_combo (const void *pa, void *foo unused) +hash_ps_combo (const void *pa, void *foo UNUSED) { const struct ps_font_combo *a = pa; unsigned name_hash = hsh_hash_string (a->font->font->internal_name); @@ -2314,7 +2302,7 @@ hash_ps_combo (const void *pa, void *foo unused) /* Hash table free function for ps_combo structs. */ static void -free_ps_combo (void *a, void *foo unused) +free_ps_combo (void *a, void *foo UNUSED) { free (a); } @@ -2413,7 +2401,7 @@ switch_font (struct outp_driver *this, const struct output_char *cp) static void write_text (struct outp_driver *this, const struct output_char *cp, const struct output_char *end, - struct outp_text *t, int width unused, int width_left) + struct outp_text *t, int width UNUSED, int width_left) { struct ps_driver_ext *ext = this->ext; int ofs; @@ -2435,6 +2423,9 @@ write_text (struct outp_driver *this, case OUTP_T_JUST_CENTER: ofs = width_left / 2; break; + default: + assert (0); + abort (); } lp = line; @@ -2475,7 +2466,7 @@ write_text (struct outp_driver *this, if (TEST_BIT (literal_chars[ext->data], cp->ch)) *lp++ = cp->ch; else - switch (cp->ch) + switch ((char) cp->ch) { case '(': lp = stpcpy (lp, "\\("); @@ -2565,18 +2556,23 @@ text (struct outp_driver *this, struct outp_text *t, int draw) buf_loc = buf; assert (!ls_null_p (&t->s)); - cp = ls_value (&t->s); + cp = ls_c_str (&t->s); end = ls_end (&t->s); if (draw) { x = t->x; y = t->y; } + else + x = y = 0; width = width_left = (t->options & OUTP_T_HORZ) ? t->h : INT_MAX; height_left = (t->options & OUTP_T_VERT) ? t->v : INT_MAX; max_height = 0; prev_char = -1; space_char = NULL; + space_buf_loc = NULL; + space_width_left = 0; + if (!width || !height_left) goto exit; @@ -2591,9 +2587,12 @@ text (struct outp_driver *this, struct outp_text *t, int draw) /* Set char_name to the name of the character or ligature at *cp. */ + local_char_name[0] = *cp; + char_name = local_char_name; if (ext->current->font->ligatures && *cp == 'f') { int lig = 0; + char_name = NULL; if (cp < end - 1) switch (cp[1]) @@ -2621,11 +2620,9 @@ text (struct outp_driver *this, struct outp_text *t, int draw) } if ((lig & ext->current->font->ligatures) == 0) { - local_char_name[0] = *cp++; /* 'f' */ + local_char_name[0] = *cp; /* 'f' */ char_name = local_char_name; } - else - cp += strlen (char_name); } else if (*cp == '\n') { @@ -2648,11 +2645,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw) set separate to 1. */ continue; } - else - { - local_char_name[0] = *cp++; - char_name = local_char_name; - } + cp += strlen (char_name); /* Figure out what size this character is, and what kern adjustment we need. */ @@ -2784,14 +2777,14 @@ exit: ext->size = old_size; } -void +static void ps_text_metrics (struct outp_driver *this, struct outp_text *t) { assert (this->driver_open && this->page_open); text (this, t, 0); } -void +static void ps_text_draw (struct outp_driver *this, struct outp_text *t) { assert (this->driver_open && this->page_open); @@ -2812,7 +2805,7 @@ static struct hsh_table *ps_fonts; /* Hash table comparison function for filename2font structs. */ static int -compare_filename2font (const void *a, const void *b, void *param unused) +compare_filename2font (const void *a, const void *b, void *param UNUSED) { return strcmp (((struct filename2font *) a)->filename, ((struct filename2font *) b)->filename); @@ -2820,7 +2813,7 @@ compare_filename2font (const void *a, const void *b, void *param unused) /* Hash table hash function for filename2font structs. */ static unsigned -hash_filename2font (const void *f2f_, void *param unused) +hash_filename2font (const void *f2f_, void *param UNUSED) { const struct filename2font *f2f = f2f_; return hsh_hash_string (f2f->filename); @@ -2835,6 +2828,12 @@ init_fonts (void) NULL, NULL); } +static void +done_fonts (void) +{ + hsh_destroy (ps_fonts); +} + /* Loads the font having Groff name DIT into THIS driver instance. Specifically, adds it into the THIS driver's `loaded' hash table. */ @@ -2882,6 +2881,86 @@ load_font (struct outp_driver *this, const char *dit) return fe; } +static void +ps_chart_initialise (struct outp_driver *this UNUSED, struct chart *ch) +{ +#ifdef NO_CHARTS + ch->lp = NULL; +#else + struct ps_driver_ext *x = this->ext; + char page_size[128]; + int size; + int x_origin, y_origin; + + ch->file = tmpfile (); + if (ch->file == NULL) + { + ch->lp = NULL; + return; + } + + size = this->width < this->length ? this->width : this->length; + x_origin = x->left_margin + (size - this->width) / 2; + y_origin = x->bottom_margin + (size - this->length) / 2; + + snprintf (page_size, sizeof page_size, + "a,xsize=%.3f,ysize=%.3f,xorigin=%.3f,yorigin=%.3f", + (double) size / PSUS, (double) size / PSUS, + (double) x_origin / PSUS, (double) y_origin / PSUS); + + ch->pl_params = pl_newplparams (); + pl_setplparam (ch->pl_params, "PAGESIZE", page_size); + ch->lp = pl_newpl_r ("ps", NULL, ch->file, stderr, ch->pl_params); +#endif +} + +static void +ps_chart_finalise (struct outp_driver *this UNUSED, struct chart *ch UNUSED) +{ +#ifndef NO_CHARTS + struct ps_driver_ext *x = this->ext; + char buf[BUFSIZ]; + static int doc_num = 0; + + if (this->page_open) + { + this->class->close_page (this); + this->page_open = 0; + } + this->class->open_page (this); + fprintf (x->file.file, + "/sp save def%s" + "%d %d translate 1000 dup scale%s" + "userdict begin%s" + "/showpage { } def%s" + "0 setgray 0 setlinecap 1 setlinewidth%s" + "0 setlinejoin 10 setmiterlimit [ ] 0 setdash newpath clear%s" + "%%%%BeginDocument: %d%s", + x->eol, + -x->left_margin, -x->bottom_margin, x->eol, + x->eol, + x->eol, + x->eol, + x->eol, + doc_num++, x->eol); + + rewind (ch->file); + while (fwrite (buf, 1, fread (buf, 1, sizeof buf, ch->file), x->file.file)) + continue; + fclose (ch->file); + + fprintf (x->file.file, + "%%%%EndDocument%s" + "end%s" + "sp restore%s", + x->eol, + x->eol, + x->eol); + this->class->close_page (this); + this->page_open = 0; +#endif +} + /* PostScript driver class. */ struct outp_class postscript_class = { @@ -2901,7 +2980,7 @@ struct outp_class postscript_class = ps_open_page, ps_close_page, - NULL, + ps_submit, ps_line_horz, ps_line_vert, @@ -2921,6 +3000,9 @@ struct outp_class postscript_class = ps_text_get_size, ps_text_metrics, ps_text_draw, + + ps_chart_initialise, + ps_chart_finalise }; /* EPSF driver class. FIXME: Probably doesn't work right. */ @@ -2942,7 +3024,7 @@ struct outp_class epsf_class = ps_open_page, ps_close_page, - NULL, + ps_submit, ps_line_horz, ps_line_vert, @@ -2962,6 +3044,10 @@ struct outp_class epsf_class = ps_text_get_size, ps_text_metrics, ps_text_draw, + + ps_chart_initialise, + ps_chart_finalise + }; #endif /* NO_POSTSCRIPT */