deroff.c 14 KB

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