1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <limits.h> 4 #include <ctype.h> 5 #include <string.h> 6 #include <unistd.h> 7 8 #undef MB_CUR_MAX 9 #define MB_CUR_MAX 3 10 11 #define NROFF (!TROFF) 12 13 /* Site dependent definitions */ 14 15 #ifndef TMACDIR 16 #define TMACDIR "lib/tmac/tmac." 17 #endif 18 #ifndef FONTDIR 19 #define FONTDIR "lib/font" 20 #endif 21 #ifndef NTERMDIR 22 #define NTERMDIR "lib/term/tab." 23 #endif 24 #ifndef TDEVNAME 25 #define TDEVNAME "post" 26 #endif 27 #ifndef NDEVNAME 28 #define NDEVNAME "37" 29 #endif 30 #ifndef TEXHYPHENS 31 #define TEXHYPHENS "/usr/lib/tex/macros/hyphen.tex" 32 #endif 33 #ifndef ALTHYPHENS 34 #define ALTHYPHENS "lib/tmac/hyphen.tex" /* another place to look */ 35 #endif 36 37 typedef unsigned char Uchar; 38 typedef unsigned short Ushort; 39 40 typedef /*unsigned*/ long Tchar; 41 42 typedef struct Blockp Blockp; 43 typedef struct Diver Diver; 44 typedef struct Stack Stack; 45 typedef struct Divsiz Divsiz; 46 typedef struct Contab Contab; 47 typedef struct Numtab Numtab; 48 typedef struct Numerr Numerr; 49 typedef struct Env Env; 50 typedef struct Term Term; 51 typedef struct Chwid Chwid; 52 typedef struct Font Font; 53 typedef struct Spnames Spnames; 54 typedef struct Wcache Wcache; 55 typedef struct Tbuf Tbuf; 56 57 /* this simulates printf into a buffer that gets flushed sporadically */ 58 /* the BSD goo is because SunOS sprintf doesn't return anything useful */ 59 60 #ifdef BSD4_2 61 #define OUT (obufp += strlen(sprintf(obufp, 62 #define PUT ))) > obuf+BUFSIZ ? flusho() : 1 63 #else 64 #define OUT (obufp += sprintf(obufp, 65 #define PUT )) > obuf+BUFSIZ ? flusho() : 1 66 #endif 67 68 #define oputs(a) OUT "%s", a PUT 69 #define oput(c) ( *obufp++ = (c), obufp > obuf+BUFSIZ ? flusho() : 1 ) 70 71 #undef sprintf /* Snow Leopard */ 72 73 extern char errbuf[]; 74 #define ERROR sprintf(errbuf, 75 #define WARN ), errprint() 76 #define FATAL ), errprint(), exit(1) 77 78 /* starting values for typesetting parameters: */ 79 80 #define PS 10 /* default point size */ 81 #define FT 1 /* default font position */ 82 #define ULFONT 2 /* default underline font */ 83 #define BDFONT 3 /* default emboldening font */ 84 #define BIFONT 4 /* default bold italic font */ 85 #define LL (unsigned) 65*INCH/10 /* line length; 39picas=6.5in */ 86 #define VS ((12*INCH)/72) /* initial vert space */ 87 88 89 #define EMPTS(pts) (((long)Inch*(pts) + 36) / 72) 90 #define EM (TROFF? EMPTS(pts): t.Em) 91 #define INCH (TROFF? Inch: 240) 92 #define HOR (TROFF? Hor: t.Adj) 93 #define VERT (TROFF? Vert: t.Vert) 94 #define PO (TROFF? Inch: 0) 95 #define SPS (TROFF? EMPTS(pts)/3: INCH/10) 96 #define SS (TROFF? 12: INCH/10) 97 #define ICS (TROFF? EMPTS(pts): 2*INCH/10) 98 #define DTAB (TROFF? (INCH/2): 0) 99 100 /* These "characters" are used to encode various internal functions 101 /* Some make use of the fact that most ascii characters between 102 /* 0 and 040 don't have any graphic or other function. 103 /* The few that do have a purpose (e.g., \n, \b, \t, ... 104 /* are avoided by the ad hoc choices here. 105 /* See ifilt[] in n1.c for others -- 1, 2, 3, 5, 6, 7, 010, 011, 012 106 */ 107 108 #define LEADER 001 109 #define IMP 004 /* impossible char; glues things together */ 110 #define TAB 011 111 #define RPT 014 /* next character is to be repeated many times */ 112 #define CHARHT 015 /* size field sets character height */ 113 #define SLANT 016 /* size field sets amount of slant */ 114 #define DRAWFCN 017 /* next several chars describe arb drawing fcns */ 115 # define DRAWLINE 'l' /* line: 'l' dx dy char */ 116 # define DRAWCIRCLE 'c' /* circle: 'c' r */ 117 # define DRAWELLIPSE 'e' /* ellipse: 'e' rx ry */ 118 # define DRAWARC 'a' /* arc: 'a' dx dy dx dy */ 119 # define DRAWSPLINE '~' /* quadratic B spline: '~' dx dy dx dy ... */ 120 /* other splines go thru too */ 121 /* NOTE: the use of ~ is a botch since it's often used in .tr commands */ 122 /* better to use a letter like s, but change it in the postprocessors too */ 123 /* for now, this is taken care of in n9.c and t10.c */ 124 # define DRAWBUILD 'b' /* built-up character (e.g., { */ 125 126 #define LEFT 020 /* \{ */ 127 #define RIGHT 021 /* \} */ 128 #define FILLER 022 /* \& and similar purposes */ 129 #define XON 023 /* \X'...' starts here */ 130 #define OHC 024 /* optional hyphenation character \% */ 131 #define CONT 025 /* \c character */ 132 #define PRESC 026 /* printable escape */ 133 #define UNPAD 027 /* unpaddable blank */ 134 #define XPAR 030 /* transparent mode indicator */ 135 #define FLSS 031 /* next Tchar contains vertical space */ 136 /* used when recalling diverted text */ 137 #define WORDSP 032 /* paddable word space */ 138 #define ESC 033 /* current escape character */ 139 #define XOFF 034 /* \X'...' ends here */ 140 /* matches XON, but they will probably never nest */ 141 /* so could drop this when another control is needed */ 142 #define HX 035 /* next character is value of \x'...' */ 143 #define MOTCH 036 /* this "character" is really motion; used by cbits() */ 144 145 #define HYPHEN c_hyphen 146 #define EMDASH c_emdash /* \(em */ 147 #define RULE c_rule /* \(ru */ 148 #define MINUS c_minus /* minus sign on current font */ 149 #define LIG_FI c_fi /* \(ff */ 150 #define LIG_FL c_fl /* \(fl */ 151 #define LIG_FF c_ff /* \(ff */ 152 #define LIG_FFI c_ffi /* \(Fi */ 153 #define LIG_FFL c_ffl /* \(Fl */ 154 #define ACUTE c_acute /* acute accent \(aa */ 155 #define GRAVE c_grave /* grave accent \(ga */ 156 #define UNDERLINE c_under /* \(ul */ 157 #define ROOTEN c_rooten /* root en \(rn */ 158 #define BOXRULE c_boxrule /* box rule \(br */ 159 #define LEFTHAND c_lefthand /* left hand for word overflow */ 160 #define DAGGER c_dagger /* dagger for end of sentence/footnote */ 161 162 #define HYPHALG 1 /* hyphenation algorithm: 0=>good old troff, 1=>tex */ 163 164 165 /* array sizes, and similar limits: */ 166 167 #define MAXFONTS 99 /* Maximum number of fonts in fontab */ 168 #define NM 91 /* requests + macros */ 169 #define NN NNAMES /* number registers */ 170 #define NNAMES 15 /* predefined reg names */ 171 #define NIF 15 /* if-else nesting */ 172 #define NS 128 /* name buffer */ 173 #define NTM 1024 /* tm buffer */ 174 #define NEV 3 /* environments */ 175 #define EVLSZ 10 /* size of ev stack */ 176 177 #define STACKSIZE (12*1024) /* stack for macros and strings in progress */ 178 #define NHYP 10 /* max hyphens per word */ 179 #define NHEX 512 /* byte size of exception word list */ 180 #define NTAB 100 /* tab stops */ 181 #define NSO 5 /* "so" depth */ 182 #define NMF 5 /* number of -m flags */ 183 #define WDSIZE 500 /* word buffer click size */ 184 #define LNSIZE 4000 /* line buffer click size */ 185 #define OLNSIZE 5000 /* output line buffer click; bigger for 'w', etc. */ 186 #define NDI 5 /* number of diversions */ 187 188 #define ALPHABET alphabet /* number of characters in basic alphabet. */ 189 /* 128 for parochial USA 7-bit ascii, */ 190 /* 256 for "European" mode with e.g., Latin-1 */ 191 192 /* NCHARS must be greater than 193 ALPHABET (ascii stuff) + total number of distinct char names 194 from all fonts that will be run in this job (including 195 unnamed ones and \N's) 196 */ 197 198 #define NCHARS (8*1024) /* maximum size of troff character set*/ 199 200 201 /* However for nroff you want only : 202 1. number of special codes in charset of DESC, which ends up being the 203 value of nchtab and which must be less than 512. 204 2. ALPHABET, which apparently is the size of the portion of the tables reserved 205 for special control symbols 206 Apparently the max N of \N is irrelevant; */ 207 /* to allow \N of up to 254 with up to 338 special characters 208 you need NCHARS of 338 + ALPHABET = 466 */ 209 210 #define NROFFCHARS 1024 /* maximum size of nroff character set */ 211 212 #define NTRTAB NCHARS /* number of items in trtab[] */ 213 #define NWIDCACHE NCHARS /* number of items in widcache[] */ 214 215 #define NTRAP 20 /* number of traps */ 216 #define NPN 20 /* numbers in "-o" */ 217 #define FBUFSZ 512 /* field buf size words */ 218 #define IBUFSZ 4096 /* bytes */ 219 #define NC 1024 /* cbuf size words */ 220 #define NOV 10 /* number of overstrike chars */ 221 #define NPP 10 /* pads per field */ 222 223 /* 224 Internal character representation: 225 Internally, every character is carried around as 226 a 32 bit cookie, called a "Tchar" (typedef long). 227 Bits are numbered 31..0 from left to right. 228 If bit 15 is 1, the character is motion, with 229 if bit 16 it's vertical motion 230 if bit 17 it's negative motion 231 If bit 15 is 0, the character is a real character. 232 if bit 31 zero motion 233 bits 30..24 size 234 bits 23..16 font 235 */ 236 237 /* in the following, "L" should really be a Tchar, but ... */ 238 /* numerology leaves room for 16 bit chars */ 239 240 #define MOT (01uL << 16) /* motion character indicator */ 241 #define VMOT (01uL << 30) /* vertical motion bit */ 242 #define NMOT (01uL << 29) /* negative motion indicator */ 243 /* #define MOTV (MOT|VMOT|NMOT) /* motion flags */ 244 /* #define MAXMOT (~MOTV) /* maximum motion permitted */ 245 #define MAXMOT 0xFFFF 246 247 #define ismot(n) ((n) & MOT) 248 #define isvmot(n) (((n) & (MOT|VMOT)) == (MOT|VMOT)) /* must have tested MOT previously */ 249 #define isnmot(n) (((n) & (MOT|NMOT)) == (MOT|NMOT)) /* ditto */ 250 #define absmot(n) ((n) & 0xFFFF) 251 252 #define ZBIT (01uL << 31) /* zero width char */ 253 #define iszbit(n) ((n) & ZBIT) 254 255 #define FSHIFT 17 256 #define SSHIFT (FSHIFT+7) 257 #define SMASK (0177uL << SSHIFT) /* 128 distinct sizes */ 258 #define FMASK (0177uL << FSHIFT) /* 128 distinct fonts */ 259 #define SFMASK (SMASK|FMASK) /* size and font in a Tchar */ 260 #define sbits(n) (((n) >> SSHIFT) & 0177) 261 #define fbits(n) (((n) >> FSHIFT) & 0177) 262 #define sfbits(n) (((n) & SFMASK) >> FSHIFT) 263 #define cbits(n) ((n) & 0x1FFFF) /* isolate character bits, */ 264 /* but don't include motions */ 265 extern int realcbits(Tchar); 266 267 #define setsbits(n,s) n = (n & ~SMASK) | (Tchar)(s) << SSHIFT 268 #define setfbits(n,f) n = (n & ~FMASK) | (Tchar)(f) << FSHIFT 269 #define setsfbits(n,sf) n = (n & ~SFMASK) | (Tchar)(sf) << FSHIFT 270 #define setcbits(n,c) n = (n & ~0xFFFFuL | (c)) /* set character bits */ 271 272 #define BYTEMASK 0377 273 #define BYTE 8 274 275 #define SHORTMASK 0XFFFF 276 #define SHORT 16 277 278 #define TABMASK ((unsigned) INT_MAX >> 1) 279 #define RTAB ((TABMASK << 1) & ~TABMASK) 280 #define CTAB (RTAB << 1) 281 282 #define TABBIT 02 /* bits in gchtab */ 283 #define LDRBIT 04 284 #define FCBIT 010 285 286 #define PAIR(A,B) (A|(B<<SHORT)) 287 288 289 extern int Inch, Hor, Vert, Unitwidth; 290 291 struct Spnames 292 { 293 int *n; 294 char *v; 295 }; 296 297 extern Spnames spnames[]; 298 299 /* 300 String and macro definitions are stored conceptually in a giant array 301 indexed by type Offset. In olden times, this array was real, and thus 302 both huge and limited in size, leading to the "Out of temp file space" 303 error. In this version, the array is represented by a list of blocks, 304 pointed to by blist[].bp. Each block is of size BLK Tchars, and BLK 305 MUST be a power of 2 for the macros below to work. 306 307 The blocks associated with a particular string or macro are chained 308 together in the array blist[]. Each blist[i].nextoff contains the 309 Offset associated with the next block in the giant array, or -1 if 310 this is the last block in the chain. If .nextoff is 0, the block is 311 free. 312 313 To find the right index in blist for an Offset, divide by BLK. 314 */ 315 316 #define NBLIST 2048 /* starting number of blocks in all definitions */ 317 318 #define BLK 128 /* number of Tchars in a block; must be 2^N with defns below */ 319 320 #define rbf0(o) (blist[bindex(o)].bp[boffset(o)]) 321 #define bindex(o) ((o) / BLK) 322 #define boffset(o) ((o) & (BLK-1)) 323 #define pastend(o) (((o) & (BLK-1)) == 0) 324 /* #define incoff(o) ( (++o & (BLK-1)) ? o : blist[bindex(o-1)].nextoff ) */ 325 #define incoff(o) ( (((o)+1) & (BLK-1)) ? o+1 : blist[bindex(o)].nextoff ) 326 327 #define skipline(f) while (getc(f) != '\n') 328 #define is(s) (strcmp(cmd, s) == 0) 329 #define eq(s1, s2) (strcmp(s1, s2) == 0) 330 331 332 typedef unsigned long Offset; /* an offset in macro/string storage */ 333 334 struct Blockp { /* info about a block: */ 335 Tchar *bp; /* the data */ 336 Offset nextoff; /* offset of next block in a chain */ 337 }; 338 339 extern Blockp *blist; 340 341 #define RD_OFFSET (1 * BLK) /* .rd command uses block 1 */ 342 343 struct Diver { /* diversion */ 344 Offset op; 345 int dnl; 346 int dimac; 347 int ditrap; 348 int ditf; 349 int alss; 350 int blss; 351 int nls; 352 int mkline; 353 int maxl; 354 int hnl; 355 int curd; 356 }; 357 358 struct Stack { /* stack frame */ 359 int nargs; 360 Stack *pframe; 361 Offset pip; 362 int pnchar; 363 Tchar prchar; 364 int ppendt; 365 Tchar pch; 366 Tchar *lastpbp; 367 int mname; 368 }; 369 370 extern Stack s; 371 372 struct Divsiz { 373 int dix; 374 int diy; 375 }; 376 377 struct Contab { /* command or macro */ 378 unsigned int rq; 379 Contab *link; 380 void (*f)(void); 381 Offset mx; 382 Offset emx; 383 Divsiz *divsiz; 384 }; 385 386 #define C(a,b) {a, 0, b, 0, 0} /* how to initialize a contab entry */ 387 388 extern Contab contab[NM]; 389 390 struct Numtab { /* number registers */ 391 unsigned int r; /* name */ 392 int val; 393 short fmt; 394 short inc; 395 Numtab *link; 396 }; 397 398 extern Numtab numtab[NN]; 399 400 #define PN 0 401 #define NL 1 402 #define YR 2 403 #define HP 3 404 #define CT 4 405 #define DN 5 406 #define MO 6 407 #define DY 7 408 #define DW 8 409 #define LN 9 410 #define DL 10 411 #define ST 11 412 #define SB 12 413 #define CD 13 414 #define PID 14 415 416 struct Wcache { /* width cache, indexed by character */ 417 short fontpts; 418 short width; 419 }; 420 421 struct Tbuf { /* growable Tchar buffer */ 422 Tchar *_bufp; 423 unsigned int _size; 424 }; 425 426 /* the infamous environment block */ 427 428 #define ics envp->_ics 429 #define sps envp->_sps 430 #define spacesz envp->_spacesz 431 #define lss envp->_lss 432 #define lss1 envp->_lss1 433 #define ll envp->_ll 434 #define ll1 envp->_ll1 435 #define lt envp->_lt 436 #define lt1 envp->_lt1 437 #define ic envp->_ic 438 #define icf envp->_icf 439 #define chbits envp->_chbits 440 #define spbits envp->_spbits 441 #define nmbits envp->_nmbits 442 #define apts envp->_apts 443 #define apts1 envp->_apts1 444 #define pts envp->_pts 445 #define pts1 envp->_pts1 446 #define font envp->_font 447 #define font1 envp->_font1 448 #define ls envp->_ls 449 #define ls1 envp->_ls1 450 #define ad envp->_ad 451 #define nms envp->_nms 452 #define ndf envp->_ndf 453 #define nmwid envp->_nmwid 454 #define fi envp->_fi 455 #define cc envp->_cc 456 #define c2 envp->_c2 457 #define ohc envp->_ohc 458 #define tdelim envp->_tdelim 459 #define hyf envp->_hyf 460 #define hyoff envp->_hyoff 461 #define hyphalg envp->_hyphalg 462 #define un1 envp->_un1 463 #define tabc envp->_tabc 464 #define dotc envp->_dotc 465 #define adsp envp->_adsp 466 #define adrem envp->_adrem 467 #define lastl envp->_lastl 468 #define nel envp->_nel 469 #define admod envp->_admod 470 #define wordp envp->_wordp 471 #define spflg envp->_spflg 472 #define linep envp->_linep 473 #define wdend envp->_wdend 474 #define wdstart envp->_wdstart 475 #define wne envp->_wne 476 #define ne envp->_ne 477 #define nc envp->_nc 478 #define nb envp->_nb 479 #define lnmod envp->_lnmod 480 #define nwd envp->_nwd 481 #define nn envp->_nn 482 #define ni envp->_ni 483 #define ul envp->_ul 484 #define cu envp->_cu 485 #define ce envp->_ce 486 #define in envp->_in 487 #define in1 envp->_in1 488 #define un envp->_un 489 #define wch envp->_wch 490 #define pendt envp->_pendt 491 #define pendw envp->_pendw 492 #define pendnf envp->_pendnf 493 #define spread envp->_spread 494 #define it envp->_it 495 #define itmac envp->_itmac 496 #define hyptr envp->_hyptr 497 #define tabtab envp->_tabtab 498 #define line envp->_line._bufp 499 #define lnsize envp->_line._size 500 #define word envp->_word._bufp 501 #define wdsize envp->_word._size 502 503 #define oline _oline._bufp 504 #define olnsize _oline._size 505 506 /* 507 * Note: 508 * If this structure changes in ni.c, you must change 509 * this as well, and vice versa. 510 */ 511 512 struct Env { 513 int _ics; 514 int _sps; 515 int _spacesz; 516 int _lss; 517 int _lss1; 518 int _ll; 519 int _ll1; 520 int _lt; 521 int _lt1; 522 Tchar _ic; 523 int _icf; 524 Tchar _chbits; 525 Tchar _spbits; 526 Tchar _nmbits; 527 int _apts; 528 int _apts1; 529 int _pts; 530 int _pts1; 531 int _font; 532 int _font1; 533 int _ls; 534 int _ls1; 535 int _ad; 536 int _nms; 537 int _ndf; 538 int _nmwid; 539 int _fi; 540 int _cc; 541 int _c2; 542 int _ohc; 543 int _tdelim; 544 int _hyf; 545 int _hyoff; 546 int _hyphalg; 547 int _un1; 548 int _tabc; 549 int _dotc; 550 int _adsp; 551 int _adrem; 552 int _lastl; 553 int _nel; 554 int _admod; 555 Tchar *_wordp; 556 int _spflg; 557 Tchar *_linep; 558 Tchar *_wdend; 559 Tchar *_wdstart; 560 int _wne; 561 int _ne; 562 int _nc; 563 int _nb; 564 int _lnmod; 565 int _nwd; 566 int _nn; 567 int _ni; 568 int _ul; 569 int _cu; 570 int _ce; 571 int _in; 572 int _in1; 573 int _un; 574 int _wch; 575 int _pendt; 576 Tchar *_pendw; 577 int _pendnf; 578 int _spread; 579 int _it; 580 int _itmac; 581 Tchar *_hyptr[NHYP]; 582 long _tabtab[NTAB]; 583 Tbuf _line; 584 Tbuf _word; 585 }; 586 587 extern Env env[]; 588 extern Env *envp; 589 590 enum { MBchar = 'U', Troffchar = 'C', Number = 'N', Install = 'i', Lookup = 'l' }; 591 /* U => utf, for instance; C => \(xx, N => \N'...' */ 592 593 594 595 struct Chwid { /* data on one character */ 596 Ushort num; /* character number: 597 0 -> not on this font 598 >= ALPHABET -> its number among all Cxy's */ 599 Ushort code; /* char code for actual device. used for \N */ 600 char *str; /* code string for nroff */ 601 Uchar wid; /* width */ 602 Uchar kern; /* ascender/descender */ 603 }; 604 605 struct Font { /* characteristics of a font */ 606 int name; /* int name, e.g., BI (2 chars) */ 607 char longname[64]; /* long name of this font (e.g., "Bembo" */ 608 char *truename; /* path name of table if not in standard place */ 609 int nchars; /* number of width entries for this font */ 610 char specfont; /* 1 == special font */ 611 int spacewidth; /* width of space on this font */ 612 int defaultwidth; /* default width of characters on this font */ 613 Chwid *wp; /* widths, etc., of the real characters */ 614 char ligfont; /* 1 == ligatures exist on this font */ 615 }; 616 617 /* ligatures, ORed into ligfont */ 618 619 #define LFF 01 620 #define LFI 02 621 #define LFL 04 622 #define LFFI 010 623 #define LFFL 020 624 625 /* tracing modes */ 626 #define TRNARGS 01 /* trace legality of numeric arguments */ 627 #define TRREQ 02 /* trace requests */ 628 #define TRMAC 04 /* trace macros */ 629 #define RQERR 01 /* processing request/macro */ 630 631 /* typewriter driving table structure */ 632 633 634 extern Term t; 635 struct Term { 636 int bset; /* these bits have to be on */ 637 int breset; /* these bits have to be off */ 638 int Hor; /* #units in minimum horiz motion */ 639 int Vert; /* #units in minimum vert motion */ 640 int Newline; /* #units in single line space */ 641 int Char; /* #units in character width */ 642 int Em; /* ditto */ 643 int Halfline; /* half line units */ 644 int Adj; /* minimum units for horizontal adjustment */ 645 char *twinit; /* initialize terminal */ 646 char *twrest; /* reinitialize terminal */ 647 char *twnl; /* terminal sequence for newline */ 648 char *hlr; /* half-line reverse */ 649 char *hlf; /* half-line forward */ 650 char *flr; /* full-line reverse */ 651 char *bdon; /* turn bold mode on */ 652 char *bdoff; /* turn bold mode off */ 653 char *iton; /* turn italic mode on */ 654 char *itoff; /* turn italic mode off */ 655 char *ploton; /* turn plot mode on */ 656 char *plotoff; /* turn plot mode off */ 657 char *up; /* sequence to move up in plot mode */ 658 char *down; /* ditto */ 659 char *right; /* ditto */ 660 char *left; /* ditto */ 661 662 Font tfont; /* widths and other info, as in a troff font */ 663 }; 664 665 extern Term t; 666 667 /* 668 * for error reporting; keep track of escapes/requests with numeric arguments 669 */ 670 struct Numerr { 671 char type; /* request or escape? */ 672 char esc; /* was escape sequence named esc */ 673 char escarg; /* argument of esc's like \D'l' */ 674 unsigned int req; /* was request or macro named req */ 675 }; 676