deroff.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. /*
  13. * Deroff command -- strip troff, eqn, and tbl sequences from
  14. * a file. Has three flags argument, -w, to cause output one word per line
  15. * rather than in the original format.
  16. * -mm (or -ms) causes the corresponding macro's to be interpreted
  17. * so that just sentences are output
  18. * -ml also gets rid of lists.
  19. * -i causes deroff to ignore .so and .nx commands.
  20. * Deroff follows .so and .nx commands, removes contents of macro
  21. * definitions, equations (both .EQ ... .EN and $...$),
  22. * Tbl command sequences, and Troff backslash vconstructions.
  23. *
  24. * All input is through the C macro; the most recently read character is in c.
  25. */
  26. /*
  27. #define C ((c = Bgetrune(infile)) < 0?\
  28. eof():\
  29. ((c == ldelim) && (filesp == files)?\
  30. skeqn():\
  31. (c == '\n'?\
  32. (linect++,c):\
  33. c)))
  34. #define C1 ((c = Bgetrune(infile)) == Beof?\
  35. eof():\
  36. (c == '\n'?\
  37. (linect++,c):\
  38. c))
  39. */
  40. /* lose those macros! */
  41. #define C fC()
  42. #define C1 fC1()
  43. #define SKIP while(C != '\n')
  44. #define SKIP1 while(C1 != '\n')
  45. #define SKIP_TO_COM SKIP;\
  46. SKIP;\
  47. pc=c;\
  48. while(C != '.' || pc != '\n' || C > 'Z')\
  49. pc=c
  50. #define YES 1
  51. #define NO 0
  52. #define MS 0
  53. #define MM 1
  54. #define ONE 1
  55. #define TWO 2
  56. #define NOCHAR -2
  57. #define EXTENDED -1 /* All runes above 0x7F */
  58. #define SPECIAL 0
  59. #define APOS 1
  60. #define PUNCT 2
  61. #define DIGIT 3
  62. #define LETTER 4
  63. int linect = 0;
  64. int wordflag= NO;
  65. int underscoreflag = NO;
  66. int msflag = NO;
  67. int iflag = NO;
  68. int mac = MM;
  69. int disp = 0;
  70. int inmacro = NO;
  71. int intable = NO;
  72. int eqnflag = 0;
  73. #define MAX_ASCII 0X80
  74. char chars[MAX_ASCII]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
  75. Rune line[30000];
  76. Rune* lp;
  77. int32_t c;
  78. int32_t pc;
  79. int ldelim = NOCHAR;
  80. int rdelim = NOCHAR;
  81. char** argv;
  82. char fname[50];
  83. Biobuf* files[15];
  84. Biobuf**filesp;
  85. Biobuf* infile;
  86. char* devnull = "/dev/null";
  87. Biobuf *infile;
  88. Biobuf bout;
  89. int32_t skeqn(void);
  90. Biobuf* opn(char *p);
  91. int eof(void);
  92. int charclass(int);
  93. void getfname(void);
  94. void fatal(char *s, char *p);
  95. void usage(void);
  96. void work(void);
  97. void putmac(Rune *rp, int vconst);
  98. void regline(int macline, int vconst);
  99. void putwords(void);
  100. void comline(void);
  101. void macro(void);
  102. void eqn(void);
  103. void tbl(void);
  104. void stbl(void);
  105. void sdis(char a1, char a2);
  106. void sce(void);
  107. void backsl(void);
  108. char* copys(char *s);
  109. void refer(int c1);
  110. void inpic(void);
  111. int
  112. fC(void)
  113. {
  114. c = Bgetrune(infile);
  115. if(c < 0)
  116. return eof();
  117. if(c == ldelim && filesp == files)
  118. return skeqn();
  119. if(c == '\n')
  120. linect++;
  121. return c;
  122. }
  123. int
  124. fC1(void)
  125. {
  126. c = Bgetrune(infile);
  127. if(c == Beof)
  128. return eof();
  129. if(c == '\n')
  130. linect++;
  131. return c;
  132. }
  133. void
  134. main(int argc, char *av[])
  135. {
  136. int i;
  137. char *f;
  138. argv = av;
  139. Binit(&bout, 1, OWRITE);
  140. ARGBEGIN{
  141. case 'w':
  142. wordflag = YES;
  143. break;
  144. case '_':
  145. wordflag = YES;
  146. underscoreflag = YES;
  147. break;
  148. case 'm':
  149. msflag = YES;
  150. if((f = ARGF()) != nil)
  151. switch(*f)
  152. {
  153. case 'm': mac = MM; break;
  154. case 's': mac = MS; break;
  155. case 'l': disp = 1; break;
  156. default: usage();
  157. }
  158. else
  159. usage();
  160. break;
  161. case 'i':
  162. iflag = YES;
  163. break;
  164. default:
  165. usage();
  166. }ARGEND
  167. if(*argv)
  168. infile = opn(*argv++);
  169. else{
  170. infile = malloc(sizeof(Biobuf));
  171. Binit(infile, 0, OREAD);
  172. }
  173. files[0] = infile;
  174. filesp = &files[0];
  175. for(i='a'; i<='z' ; ++i)
  176. chars[i] = LETTER;
  177. for(i='A'; i<='Z'; ++i)
  178. chars[i] = LETTER;
  179. for(i='0'; i<='9'; ++i)
  180. chars[i] = DIGIT;
  181. chars['\''] = APOS;
  182. chars['&'] = APOS;
  183. chars['\b'] = APOS;
  184. chars['.'] = PUNCT;
  185. chars[','] = PUNCT;
  186. chars[';'] = PUNCT;
  187. chars['?'] = PUNCT;
  188. chars[':'] = PUNCT;
  189. work();
  190. }
  191. int32_t
  192. skeqn(void)
  193. {
  194. while(C1 != rdelim)
  195. if(c == '\\')
  196. c = C1;
  197. else if(c == '"')
  198. while(C1 != '"')
  199. if(c == '\\')
  200. C1;
  201. if (msflag)
  202. eqnflag = 1;
  203. return(c = ' ');
  204. }
  205. Biobuf*
  206. opn(char *p)
  207. {
  208. Biobuf *fd;
  209. while ((fd = Bopen(p, OREAD)) == 0) {
  210. if(msflag || p == devnull)
  211. fatal("Cannot open file %s - quitting\n", p);
  212. else {
  213. fprint(2, "Deroff: Cannot open file %s - continuing\n", p);
  214. p = devnull;
  215. }
  216. }
  217. linect = 0;
  218. return(fd);
  219. }
  220. int
  221. eof(void)
  222. {
  223. if(Bfildes(infile) != 0)
  224. Bterm(infile);
  225. if(filesp > files)
  226. infile = *--filesp;
  227. else
  228. if(*argv)
  229. infile = opn(*argv++);
  230. else
  231. exits(0);
  232. return(C);
  233. }
  234. void
  235. getfname(void)
  236. {
  237. char *p;
  238. Rune r;
  239. Dir *dir;
  240. struct chain
  241. {
  242. struct chain* nextp;
  243. char* datap;
  244. } *q;
  245. static struct chain *namechain= 0;
  246. while(C == ' ')
  247. ;
  248. for(p = fname; (r=c) != '\n' && r != ' ' && r != '\t' && r != '\\'; C)
  249. p += runetochar(p, &r);
  250. *p = '\0';
  251. while(c != '\n')
  252. C;
  253. if(!strcmp(fname, "/sys/lib/tmac/tmac.cs")
  254. || !strcmp(fname, "/sys/lib/tmac/tmac.s")) {
  255. fname[0] = '\0';
  256. return;
  257. }
  258. dir = dirstat(fname);
  259. if(dir!=nil && ((dir->mode & DMDIR) || dir->type != 'M')) {
  260. free(dir);
  261. fname[0] = '\0';
  262. return;
  263. }
  264. free(dir);
  265. /*
  266. * see if this name has already been used
  267. */
  268. for(q = namechain; q; q = q->nextp)
  269. if( !strcmp(fname, q->datap)) {
  270. fname[0] = '\0';
  271. return;
  272. }
  273. q = (struct chain*)malloc(sizeof(struct chain));
  274. q->nextp = namechain;
  275. q->datap = copys(fname);
  276. namechain = q;
  277. }
  278. void
  279. usage(void)
  280. {
  281. fprint(2,"usage: deroff [-nw_pi] [-m (m s l)] [file ...] \n");
  282. exits("usage");
  283. }
  284. void
  285. fatal(char *s, char *p)
  286. {
  287. fprint(2, "deroff: ");
  288. fprint(2, s, p);
  289. exits(s);
  290. }
  291. void
  292. work(void)
  293. {
  294. for(;;) {
  295. eqnflag = 0;
  296. if(C == '.' || c == '\'')
  297. comline();
  298. else
  299. regline(NO, TWO);
  300. }
  301. }
  302. void
  303. regline(int macline, int vconst)
  304. {
  305. line[0] = c;
  306. lp = line;
  307. for(;;) {
  308. if(c == '\\') {
  309. *lp = ' ';
  310. backsl();
  311. if(c == '%') /* no blank for hyphenation char */
  312. lp--;
  313. }
  314. if(c == '\n')
  315. break;
  316. if(intable && c=='T') {
  317. *++lp = C;
  318. if(c=='{' || c=='}') {
  319. lp[-1] = ' ';
  320. *lp = C;
  321. }
  322. } else {
  323. if(msflag == 1 && eqnflag == 1) {
  324. eqnflag = 0;
  325. *++lp = 'x';
  326. }
  327. *++lp = C;
  328. }
  329. }
  330. *lp = '\0';
  331. if(lp != line) {
  332. if(wordflag)
  333. putwords();
  334. else
  335. if(macline)
  336. putmac(line,vconst);
  337. else
  338. Bprint(&bout, "%S\n", line);
  339. }
  340. }
  341. void
  342. putmac(Rune *rp, int vconst)
  343. {
  344. Rune *t;
  345. int found;
  346. Rune last;
  347. found = 0;
  348. last = 0;
  349. while(*rp) {
  350. while(*rp == ' ' || *rp == '\t')
  351. Bputrune(&bout, *rp++);
  352. for(t = rp; *t != ' ' && *t != '\t' && *t != '\0'; t++)
  353. ;
  354. if(*rp == '\"')
  355. rp++;
  356. if(t > rp+vconst && charclass(*rp) == LETTER
  357. && charclass(rp[1]) == LETTER) {
  358. while(rp < t)
  359. if(*rp == '\"')
  360. rp++;
  361. else
  362. Bputrune(&bout, *rp++);
  363. last = t[-1];
  364. found++;
  365. } else
  366. if(found && charclass(*rp) == PUNCT && rp[1] == '\0')
  367. Bputrune(&bout, *rp++);
  368. else {
  369. last = t[-1];
  370. rp = t;
  371. }
  372. }
  373. Bputc(&bout, '\n');
  374. if(msflag && charclass(last) == PUNCT)
  375. Bprint(&bout, " %C\n", last);
  376. }
  377. /*
  378. * break into words for -w option
  379. */
  380. void
  381. putwords(void)
  382. {
  383. Rune *p, *p1;
  384. int i, nlet;
  385. for(p1 = line;;) {
  386. /*
  387. * skip initial specials ampersands and apostrophes
  388. */
  389. while((i = charclass(*p1)) != EXTENDED && i < DIGIT)
  390. if(*p1++ == '\0')
  391. return;
  392. nlet = 0;
  393. for(p = p1; (i = charclass(*p)) != SPECIAL || (underscoreflag && *p=='_'); p++)
  394. if(i == LETTER || (underscoreflag && *p == '_'))
  395. nlet++;
  396. /*
  397. * MDM definition of word
  398. */
  399. if(nlet > 1) {
  400. /*
  401. * delete trailing ampersands and apostrophes
  402. */
  403. while(*--p == '\'' || *p == '&'
  404. || charclass(*p) == PUNCT)
  405. ;
  406. while(p1 <= p)
  407. Bputrune(&bout, *p1++);
  408. Bputc(&bout, '\n');
  409. } else
  410. p1 = p;
  411. }
  412. }
  413. void
  414. comline(void)
  415. {
  416. int32_t c1, c2;
  417. while(C==' ' || c=='\t')
  418. ;
  419. comx:
  420. if((c1=c) == '\n')
  421. return;
  422. c2 = C;
  423. if(c1=='.' && c2!='.')
  424. inmacro = NO;
  425. if(msflag && c1 == '['){
  426. refer(c2);
  427. return;
  428. }
  429. if(c2 == '\n')
  430. return;
  431. if(c1 == '\\' && c2 == '\"')
  432. SKIP;
  433. else
  434. if (filesp==files && c1=='E' && c2=='Q')
  435. eqn();
  436. else
  437. if(filesp==files && c1=='T' && (c2=='S' || c2=='C' || c2=='&')) {
  438. if(msflag)
  439. stbl();
  440. else
  441. tbl();
  442. }
  443. else
  444. if(c1=='T' && c2=='E')
  445. intable = NO;
  446. else if (!inmacro &&
  447. ((c1 == 'd' && c2 == 'e') ||
  448. (c1 == 'i' && c2 == 'g') ||
  449. (c1 == 'a' && c2 == 'm')))
  450. macro();
  451. else
  452. if(c1=='s' && c2=='o') {
  453. if(iflag)
  454. SKIP;
  455. else {
  456. getfname();
  457. if(fname[0]) {
  458. if((infile = opn(fname)) != nil)
  459. *++filesp = infile;
  460. else infile = *filesp;
  461. }
  462. }
  463. }
  464. else
  465. if(c1=='n' && c2=='x')
  466. if(iflag)
  467. SKIP;
  468. else {
  469. getfname();
  470. if(fname[0] == '\0')
  471. exits(0);
  472. if(Bfildes(infile) != 0)
  473. Bterm(infile);
  474. infile = *filesp = opn(fname);
  475. }
  476. else
  477. if(c1 == 't' && c2 == 'm')
  478. SKIP;
  479. else
  480. if(c1=='h' && c2=='w')
  481. SKIP;
  482. else
  483. if(msflag && c1 == 'T' && c2 == 'L') {
  484. SKIP_TO_COM;
  485. goto comx;
  486. }
  487. else
  488. if(msflag && c1=='N' && c2 == 'R')
  489. SKIP;
  490. else
  491. if(msflag && c1 == 'A' && (c2 == 'U' || c2 == 'I')){
  492. if(mac==MM)SKIP;
  493. else {
  494. SKIP_TO_COM;
  495. goto comx;
  496. }
  497. } else
  498. if(msflag && c1=='F' && c2=='S') {
  499. SKIP_TO_COM;
  500. goto comx;
  501. }
  502. else
  503. if(msflag && (c1=='S' || c1=='N') && c2=='H') {
  504. SKIP_TO_COM;
  505. goto comx;
  506. } else
  507. if(c1 == 'U' && c2 == 'X') {
  508. if(wordflag)
  509. Bprint(&bout, "UNIX\n");
  510. else
  511. Bprint(&bout, "UNIX ");
  512. } else
  513. if(msflag && c1=='O' && c2=='K') {
  514. SKIP_TO_COM;
  515. goto comx;
  516. } else
  517. if(msflag && c1=='N' && c2=='D')
  518. SKIP;
  519. else
  520. if(msflag && mac==MM && c1=='H' && (c2==' '||c2=='U'))
  521. SKIP;
  522. else
  523. if(msflag && mac==MM && c2=='L') {
  524. if(disp || c1=='R')
  525. sdis('L', 'E');
  526. else {
  527. SKIP;
  528. Bprint(&bout, " .");
  529. }
  530. } else
  531. if(!msflag && c1=='P' && c2=='S') {
  532. inpic();
  533. } else
  534. if(msflag && (c1=='D' || c1=='N' || c1=='K'|| c1=='P') && c2=='S') {
  535. sdis(c1, 'E');
  536. } else
  537. if(msflag && (c1 == 'K' && c2 == 'F')) {
  538. sdis(c1,'E');
  539. } else
  540. if(msflag && c1=='n' && c2=='f')
  541. sdis('f','i');
  542. else
  543. if(msflag && c1=='c' && c2=='e')
  544. sce();
  545. else {
  546. if(c1=='.' && c2=='.') {
  547. if(msflag) {
  548. SKIP;
  549. return;
  550. }
  551. while(C == '.')
  552. ;
  553. }
  554. inmacro++;
  555. if(c1 <= 'Z' && msflag)
  556. regline(YES,ONE);
  557. else {
  558. if(wordflag)
  559. C;
  560. regline(YES,TWO);
  561. }
  562. inmacro--;
  563. }
  564. }
  565. void
  566. macro(void)
  567. {
  568. if(msflag) {
  569. do {
  570. SKIP1;
  571. } while(C1 != '.' || C1 != '.' || C1 == '.');
  572. if(c != '\n')
  573. SKIP;
  574. return;
  575. }
  576. SKIP;
  577. inmacro = YES;
  578. }
  579. void
  580. sdis(char a1, char a2)
  581. {
  582. int c1, c2;
  583. int eqnf;
  584. int lct;
  585. if(a1 == 'P'){
  586. while(C1 == ' ')
  587. ;
  588. if(c == '<') {
  589. SKIP1;
  590. return;
  591. }
  592. }
  593. lct = 0;
  594. eqnf = 1;
  595. if(c != '\n')
  596. SKIP1;
  597. for(;;) {
  598. while(C1 != '.')
  599. if(c == '\n')
  600. continue;
  601. else
  602. SKIP1;
  603. if((c1=C1) == '\n')
  604. continue;
  605. if((c2=C1) == '\n') {
  606. if(a1 == 'f' && (c1 == 'P' || c1 == 'H'))
  607. return;
  608. continue;
  609. }
  610. if(c1==a1 && c2 == a2) {
  611. SKIP1;
  612. if(lct != 0){
  613. lct--;
  614. continue;
  615. }
  616. if(eqnf)
  617. Bprint(&bout, " .");
  618. Bputc(&bout, '\n');
  619. return;
  620. } else
  621. if(a1 == 'L' && c2 == 'L') {
  622. lct++;
  623. SKIP1;
  624. } else
  625. if(a1 == 'D' && c1 == 'E' && c2 == 'Q') {
  626. eqn();
  627. eqnf = 0;
  628. } else
  629. if(a1 == 'f') {
  630. if((mac == MS && c2 == 'P') ||
  631. (mac == MM && c1 == 'H' && c2 == 'U')){
  632. SKIP1;
  633. return;
  634. }
  635. SKIP1;
  636. }
  637. else
  638. SKIP1;
  639. }
  640. }
  641. void
  642. tbl(void)
  643. {
  644. while(C != '.')
  645. ;
  646. SKIP;
  647. intable = YES;
  648. }
  649. void
  650. stbl(void)
  651. {
  652. while(C != '.')
  653. ;
  654. SKIP_TO_COM;
  655. if(c != 'T' || C != 'E') {
  656. SKIP;
  657. pc = c;
  658. while(C != '.' || pc != '\n' || C != 'T' || C != 'E')
  659. pc = c;
  660. }
  661. }
  662. void
  663. eqn(void)
  664. {
  665. int32_t c1, c2;
  666. int dflg;
  667. char last;
  668. last = 0;
  669. dflg = 1;
  670. SKIP;
  671. for(;;) {
  672. if(C1 == '.' || c == '\'') {
  673. while(C1==' ' || c=='\t')
  674. ;
  675. if(c=='E' && C1=='N') {
  676. SKIP;
  677. if(msflag && dflg) {
  678. Bputc(&bout, 'x');
  679. Bputc(&bout, ' ');
  680. if(last) {
  681. Bputc(&bout, last);
  682. Bputc(&bout, '\n');
  683. }
  684. }
  685. return;
  686. }
  687. } else
  688. if(c == 'd') {
  689. if(C1=='e' && C1=='l')
  690. if(C1=='i' && C1=='m') {
  691. while(C1 == ' ')
  692. ;
  693. if((c1=c)=='\n' || (c2=C1)=='\n' ||
  694. (c1=='o' && c2=='f' && C1=='f')) {
  695. ldelim = NOCHAR;
  696. rdelim = NOCHAR;
  697. } else {
  698. ldelim = c1;
  699. rdelim = c2;
  700. }
  701. }
  702. dflg = 0;
  703. }
  704. if(c != '\n')
  705. while(C1 != '\n') {
  706. if(chars[c] == PUNCT)
  707. last = c;
  708. else
  709. if(c != ' ')
  710. last = 0;
  711. }
  712. }
  713. }
  714. /*
  715. * skip over a complete backslash vconstruction
  716. */
  717. void
  718. backsl(void)
  719. {
  720. int bdelim;
  721. sw:
  722. switch(C1)
  723. {
  724. case '"':
  725. SKIP1;
  726. return;
  727. case 's':
  728. if(C1 == '\\')
  729. backsl();
  730. else {
  731. while(C1>='0' && c<='9')
  732. ;
  733. Bungetrune(infile);
  734. c = '0';
  735. }
  736. lp--;
  737. return;
  738. case 'f':
  739. case 'n':
  740. case '*':
  741. if(C1 != '(')
  742. return;
  743. case '(':
  744. if(msflag) {
  745. if(C == 'e') {
  746. if(C1 == 'm') {
  747. *lp = '-';
  748. return;
  749. }
  750. } else
  751. if(c != '\n')
  752. C1;
  753. return;
  754. }
  755. if(C1 != '\n')
  756. C1;
  757. return;
  758. case '$':
  759. C1; /* discard argument number */
  760. return;
  761. case 'b':
  762. case 'x':
  763. case 'v':
  764. case 'h':
  765. case 'w':
  766. case 'o':
  767. case 'l':
  768. case 'L':
  769. if((bdelim=C1) == '\n')
  770. return;
  771. while(C1!='\n' && c!=bdelim)
  772. if(c == '\\')
  773. backsl();
  774. return;
  775. case '\\':
  776. if(inmacro)
  777. goto sw;
  778. default:
  779. return;
  780. }
  781. }
  782. char*
  783. copys(char *s)
  784. {
  785. char *t, *t0;
  786. if((t0 = t = malloc((strlen(s)+1))) == 0)
  787. fatal("Cannot allocate memory", (char*)0);
  788. while((*t++ = *s++) != '\0')
  789. ;
  790. return(t0);
  791. }
  792. void
  793. sce(void)
  794. {
  795. int n = 1;
  796. while (C != L'\n' && !(L'0' <= c && c <= L'9'))
  797. ;
  798. if (c != L'\n') {
  799. for (n = c-L'0';'0' <= C && c <= L'9';)
  800. n = n*10 + c-L'0';
  801. }
  802. while(n) {
  803. if(C == '.') {
  804. if(C == 'c') {
  805. if(C == 'e') {
  806. while(C == ' ')
  807. ;
  808. if(c == '0') {
  809. SKIP;
  810. break;
  811. } else
  812. SKIP;
  813. } else
  814. SKIP;
  815. } else
  816. if(c == 'P' || C == 'P') {
  817. if(c != '\n')
  818. SKIP;
  819. break;
  820. } else
  821. if(c != '\n')
  822. SKIP;
  823. } else {
  824. SKIP;
  825. n--;
  826. }
  827. }
  828. }
  829. void
  830. refer(int c1)
  831. {
  832. int c2;
  833. if(c1 != '\n')
  834. SKIP;
  835. c2 = 0;
  836. for(;;) {
  837. if(C != '.')
  838. SKIP;
  839. else {
  840. if(C != ']')
  841. SKIP;
  842. else {
  843. while(C != '\n')
  844. c2 = c;
  845. if(charclass(c2) == PUNCT)
  846. Bprint(&bout, " %C",c2);
  847. return;
  848. }
  849. }
  850. }
  851. }
  852. void
  853. inpic(void)
  854. {
  855. int c1;
  856. Rune *p1;
  857. /* SKIP1;*/
  858. while(C1 != '\n')
  859. if(c == '<'){
  860. SKIP1;
  861. return;
  862. }
  863. p1 = line;
  864. c = '\n';
  865. for(;;) {
  866. c1 = c;
  867. if(C1 == '.' && c1 == '\n') {
  868. if(C1 != 'P' || C1 != 'E') {
  869. if(c != '\n'){
  870. SKIP1;
  871. c = '\n';
  872. }
  873. continue;
  874. }
  875. SKIP1;
  876. return;
  877. } else
  878. if(c == '\"') {
  879. while(C1 != '\"') {
  880. if(c == '\\') {
  881. if(C1 == '\"')
  882. continue;
  883. Bungetrune(infile);
  884. backsl();
  885. } else
  886. *p1++ = c;
  887. }
  888. *p1++ = ' ';
  889. } else
  890. if(c == '\n' && p1 != line) {
  891. *p1 = '\0';
  892. if(wordflag)
  893. putwords();
  894. else
  895. Bprint(&bout, "%S\n\n", line);
  896. p1 = line;
  897. }
  898. }
  899. }
  900. int
  901. charclass(int c)
  902. {
  903. if(c < MAX_ASCII)
  904. return chars[c];
  905. switch(c){
  906. case 0x2013: case 0x2014: /* en dash, em dash */
  907. return SPECIAL;
  908. }
  909. return EXTENDED;
  910. }