1 /*
2 * Copyright (C) 1991,1992,1993 NEC Corporation.
3 */
4 #ifndef lint
5 static char rcsid[] =
6 "$Id: miscutil.c,v 2.15 1994/04/19 10:16:50 uchida Exp $ (NEC)";
7 #endif
8
9 #include <stdio.h>
10 #include "plain2.h"
11 #include "kanji.h"
12 #include <ctype.h>
13 #ifdef MSDOS
14 /*
15 * get option letter from argument vector
16 */
17 int opterr = 1, /* useless, never set or used */
18 optind = 1, /* index into parent argv vector */
19 optopt; /* character checked for validity */
20 char *optarg; /* argument associated with option */
21
22 #define BADCH (int)'?'
23 #define EMSG ""
24 #define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \
25 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
getopt(nargc,nargv,ostr)26 getopt(nargc,nargv,ostr)
27 int nargc;
28 char **nargv,
29 *ostr;
30 {
31 static char *place = EMSG; /* option letter processing */
32 register char *oli; /* option letter list index */
33
34 if(!*place) { /* update scanning pointer */
35 if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
36 if (*place == '-') { /* found "--" */
37 ++optind;
38 return(EOF);
39 }
40 } /* option letter okay? */
41 if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
42 if(!*place) ++optind;
43 tell(": illegal option -- ");
44 }
45 if (*++oli != ':') { /* don't need argument */
46 optarg = NULL;
47 if (!*place) ++optind;
48 }
49 else { /* need an argument */
50 if (*place) optarg = place; /* no white space */
51 else if (nargc <= ++optind) { /* no arg */
52 place = EMSG;
53 tell(": option requires an argument -- ");
54 }
55 else optarg = nargv[optind]; /* white space */
56 place = EMSG;
57 ++optind;
58 }
59 return(optopt); /* dump back option letter */
60 }
61 #endif
62 /*
63 * Value of number string(hankaku or Zenkaku)
64 * return rest of the string
65 */
66 char *
strNum(str,rval)67 strNum(str, rval)
68 char *str;
69 int *rval;
70 {
71 *rval = 0;
72 while(1) {
73 if (
74 #ifdef KANJI
75 !isZenkaku(str) &&
76 #endif
77 isdigit(*str)){
78 *rval = *rval * 10 + (*str - '0');
79 str++;
80 }
81 #ifdef KANJI
82 else if (maybeZenkakuNum(str)) {
83 /* Zenkaku Number */
84 *rval = *rval * 10 + ZenkakuNumVal(str);
85 str += 2;
86 }
87 #endif
88 else {
89 /* search Next number */
90 while (*str) {
91 #ifdef KANJI
92 if (maybeZenkakuNum(str))
93 break;
94 if (isZenkaku(str))
95 str += 2;
96 else
97 #endif
98 if (isdigit(*str))
99 break;
100 else
101 str++;
102 }
103 return str;
104 }
105 }
106 }
107 #ifdef KANJI
108 char *
euc2jisStr(str,jstr)109 euc2jisStr(str, jstr)
110 char *str;
111 char *jstr;
112 {
113 char *t = jstr;
114 int inKanji = 0;
115 while(*str) {
116 if (t >= jstr + MAX_LINE_LEN) {
117 fprintf(stderr, "PANIC(buffer overflow in jis convert)\n");
118 exit(2);
119 }
120 if (!inKanji && isZenkaku(str)) {
121 (void)strncpy(t,"\033$B", 3);
122 t += 3;
123 inKanji = 1;
124 }
125 else if (inKanji && !isZenkaku(str)) {
126 (void)strncpy(t,"\033(B", 3);
127 t += 3;
128 inKanji = 0;
129 }
130 *t++ = *str++ & 0x7f;
131 if (t > jstr + MAX_LINE_LEN) {
132 fprintf(stderr, "PANIC(buffer overflow in jis convert)\n");
133 exit(2);
134 }
135 }
136 if (inKanji) {
137 (void)strncpy(t,"\033(B", 3);
138 t += 3;
139 }
140 *t = '\0';
141 return jstr;
142 }
143 char *
euc2sftjStr(str,sjstr)144 euc2sftjStr(str, sjstr)
145 char *str;
146 char *sjstr;
147 {
148 register char c1, c2;
149 char *t = sjstr;
150 while(*str) {
151 if (isZenkaku(str)) {
152 c2 = (*str++) & 0x7f;
153 c1 = (*str++) & 0x7f;
154 *t++ = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
155 *t++ = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
156 }
157 else {
158 *t++ = *str++;
159 }
160 }
161 *t = '\0';
162 return sjstr;
163 }
164 #define isSjKanji(c) (((c)>=0x80 && (c)<0xa0) || ((c)>=0xe0 && (c)<0xfd))
165 char *
sftj2eucStr(str,estr)166 sftj2eucStr(str, estr)
167 char *str;
168 char *estr;
169 {
170 int c1, c2;
171 char *t = estr;
172 while(*str) {
173 c1 = (unsigned char)*str++;
174 if (isSjKanji(c1)) {
175 c2 = (unsigned char)*str++;
176 if (c2 >= 0x9f) {
177 *t++ = (c1 >= 0xe0)?
178 c1*2 - 0xe0 : c1*2 - 0x60;
179 *t++ = c2 + 2;
180 } else {
181 *t++ = (c1 >= 0xe0)?
182 c1*2 - 0xe1 : c1*2 - 0x61;
183 *t++ = (c2 >= 0x7f)?
184 c2 + 0x60 : c2 + 0x61;
185 }
186 }
187 else {
188 *t++ = c1;
189 }
190 }
191 *t = '\0';
192 return estr;
193 }
194 #endif
195 char *
codeCvt(str)196 codeCvt(str)
197 char *str;
198 {
199 #ifdef KANJI
200 #if INTERNAL_CODE == CODE_EUC
201 static char cvtBuf[MAX_LINE_LEN];
202 if (outputCode == CODE_JIS)
203 return euc2jisStr(str, cvtBuf);
204 else if (outputCode == CODE_SJIS)
205 return euc2sftjStr(str, cvtBuf);
206 else
207 return str;
208 #else
209 #if INTERNAL_CODE == CODE_SJIS
210 return str;
211 #else
212 unknown code;
213 #endif
214 #endif
215 #else
216 return str;
217 #endif
218 }
219 minIndentBlock(tbp)
220 struct textBlock *tbp;
221 {
222 if (tbp->type == TB_LIST) {
223 return texts[tbp->rbegin]->indent;
224 }
225 return minIndent(tbp->rbegin + tbp->hinted, tbp->rend - tbp->hinted);
226 }
minIndent(begin,end)227 minIndent(begin, end)
228 int begin;
229 int end;
230 {
231 register int i;
232 register int mini, indent;
233 mini = texts[begin]->indent;
234 for (i = begin; i < end; i++) {
235 indent = texts[i]->indent;
236 if (!texts[i]->blank && indent < mini)
237 if ((mini = indent) == 0)
238 return 0;
239 }
240 return mini;
241 }
maxLength(begin,end)242 maxLength(begin, end)
243 int begin;
244 int end;
245 {
246 int maxl;
247 int i;
248 maxl = 0;
249 for (i = begin; i < end; i++) {
250 if (texts[i]->length > maxl)
251 maxl = texts[i]->length;
252 }
253 return maxl;
254 }
isCenter(begin,end)255 isCenter(begin, end)
256 int begin;
257 int end;
258 {
259 int left, right;
260 left = minIndent(begin, end);
261 right= rightMargin - maxLength(begin, end);
262 if (right < 0)
263 return (left <= MIN_INDENT);
264 if (left > MIN_INDENT && right < rightMargin/4)
265 return 1;
266 if ((left * 2) <= (right * 5) &&
267 (left * 5) >= (right * 2))
268 return 1;
269 return 0;
270 }
271 blockIsCenter(tbp)
272 struct textBlock *tbp;
273 {
274 return isCenter(tbp->rbegin, tbp->rend);
275 }
276 char *
listSecBody(textp)277 listSecBody(textp)
278 struct text *textp;
279 {
280 char *s;
281 s = textp->body + textp->indent + textp->headLen;
282 while (*s != '\0') {
283 if (*s != ' ')
284 break;
285 s++;
286 }
287 return s;
288 }
textQuoteChar(top,s,trtp)289 textQuoteChar(top, s, trtp)
290 register char **top;
291 register char *s;
292 register struct transTable *trtp;
293 {
294 register char *tto;
295 for (; trtp->special_char != 0; trtp++) {
296 if (*s == trtp->special_char) {
297 for (tto=trtp->trans_to; *tto!= '\0'; tto++)
298 *(*top)++ = *tto;
299 return;
300 }
301 }
302 *(*top)++ = *s;
303 }
304 char *
textQuote(str,tr_table)305 textQuote(str, tr_table)
306 register char *str;
307 struct transTable *tr_table;
308 {
309 static char translated[MAX_LINE_LEN];
310 char *t;
311 if (rawOutput)
312 return str;
313 t = translated;
314 for(; *str != '\0'; str++) {
315 #ifdef KANJI
316 if (isZenkaku(str)) {
317 *t++ = *str++;
318 *t++ = *str;
319 }
320 else
321 #endif
322 textQuoteChar(&t, str, tr_table);
323 }
324 *t = '\0';
325 return translated;
326 }
327 /*
328 * Blank line structure (Blank:true, Length:0)
329 */
330 static struct text blank =
331 {
332 NULL, NULL, 1,
333 0, 0, 0, 0,
334 0
335 };
336 struct text *
prevLine(lnum)337 prevLine(lnum)
338 int lnum;
339 {
340 if (lnum <= textBegin)
341 return ␣
342 return (texts[lnum-1]);
343 }
344 struct text *
nextLine(lnum)345 nextLine(lnum)
346 int lnum;
347 {
348 if (lnum+1 >= textLines)
349 return ␣
350 return (texts[lnum+1]);
351 }
352 struct textBlock *
prevBlock(lnum,bound)353 prevBlock(lnum, bound)
354 int lnum;
355 int bound;
356 {
357 while(--lnum >= bound) {
358 if (texts[lnum]->block) {
359 if (texts[lnum]->block->superBlock)
360 return texts[lnum]->block->superBlock;
361 else
362 return texts[lnum]->block;
363 }
364 }
365 return NULL;
366 }
367 struct textBlock *
nextBlock(lnum,bound)368 nextBlock(lnum, bound)
369 int lnum;
370 int bound;
371 {
372 for( ;lnum < bound; lnum++) {
373 if (texts[lnum]->block) {
374 if (texts[lnum]->block->superBlock)
375 return texts[lnum]->block->superBlock;
376 else
377 return texts[lnum]->block;
378 }
379 }
380 return NULL;
381 }
382 #ifdef KANJI
383 /*
384 * Character at column "col" in string "s" is kanji character
385 */
isKanjiChar(textp,col)386 isKanjiChar(textp, col)
387 register struct text *textp;
388 register short col;
389 {
390 register char *s;
391 if (col > textp->length || col < textp->indent)
392 return 0;
393 s = textp->body + textp->indent;
394 col -= textp->indent;
395 for (; *s && col > 0; s++, col--) {
396 if (isZenkaku(s)) {
397 s++;
398 col--;
399 }
400 }
401 if (col == 0 && isZenkaku(s))
402 return 1;
403 return 0;
404 }
405 #endif
406 struct textBlock *
newTextBlock(begin,end,type)407 newTextBlock(begin, end, type)
408 int begin;
409 int end;
410 int type;
411 {
412 struct textBlock *tbp;
413 tbp = (struct textBlock *)malloc(sizeof(struct textBlock));
414 if (tbp == NULL) {
415 fprintf(stderr, "PANIC(malloc in newTextBlock)\n");
416 exit (2);
417 }
418 bzero((char *)tbp, sizeof(struct textBlock));
419 tbp->rbegin = begin;
420 tbp->rend = end;
421 tbp->hinted = 0;
422 tbp->type = type;
423 return tbp;
424 }
425 #define S_START 1
426 #define S_SPACED 2
427 #define S_INDENTED 3
428 /*
429 * phase-0: 1, 2, 3
430 * phase-1: 4, 5, 6
431 *
432 * +- + ------------------------
433 * 4 | ------------------------
434 * +- | ------------------------
435 * | + ----------------
436 * 1 2 3 --------
437 * | + ----------------
438 * +- + ------------------------
439 * 5 ------------------------
440 * +- ------------------------
441 *
442 * +- ------------------------
443 * 6 ------------------------
444 * +- ------------------------
445 */
applyOnRegion2(begin,end,phase,func)446 applyOnRegion2(begin, end, phase, func)
447 int begin;
448 int end;
449 int phase;
450 int (*func)();
451 {
452 register int l;
453 register struct text *textp;
454 int rstat, indent;
455 int rbegin, ibegin, rend;
456 DBG3(8, "applyOnRegion-%d (%d-%d)\n", phase, begin, end);
457 rstat = S_START;
458 indent = minIndent(begin, end);
459 rbegin = begin;
460 for (l = begin; l <= end; l++) {
461 textp = texts[l];
462 switch (rstat) {
463 case S_START:
464 DBG1(11, "aor START %d\n", l);
465 if (l >= end)
466 break;
467 else if (!textp->blank
468 && textp->block == NULL) {
469 if (textp->indent >= indent + MIN_INDENT) {
470 ibegin = l;
471 rend = l + 1;
472 rstat = S_INDENTED;
473 }
474 else {
475 rbegin = l;
476 rstat = S_SPACED;
477 }
478 }
479 break;
480 case S_SPACED:
481 DBG2(11, "aor SPACED %d B:%d\n", l, rbegin);
482 if (l >= end
483 || textp->blank
484 || textp->block != NULL) {
485 if (phase == 1)
486 (*func)(rbegin, l<end?l:end);
487 rstat = S_START;
488 }
489 else if (textp->indent >= indent + MIN_INDENT) {
490 ibegin = l;
491 rend = l + 1;
492 rstat = S_INDENTED;
493 }
494 break;
495 case S_INDENTED:
496 DBG2(11, "aor INDENTED %d B:%d\n", l, rbegin);
497 if (l == end
498 || (!textp->blank
499 && textp->indent < indent + MIN_INDENT)){
500 if (phase == 0
501 && !texts[rbegin]->japanese) /* XXX */
502 (*func)(rbegin, (l+1)<end?(l+1):end-1);
503 if (phase == 0 && (*func)(ibegin, rend) == 0)
504 applyOnRegion(ibegin, rend, func);
505 rbegin = l;
506 rstat = S_SPACED;
507 }
508 else if (!isBlank(l))
509 rend = l + 1;
510 else if (!textp->blank
511 && textp->block == NULL)
512 return;
513 break;
514 default:
515 fprintf(stderr, "PANIC(undefined status)%d\n", rstat);
516 exit(2);
517 }
518 }
519 }
applyOnRegion(begin,end,func)520 applyOnRegion(begin, end, func)
521 int begin;
522 int end;
523 int (*func)();
524 {
525 applyOnRegion2(begin, end, 0, func);
526 applyOnRegion2(begin, end, 1, func);
527 }
applyOnSpaced(begin,end,func)528 applyOnSpaced(begin, end, func)
529 int begin;
530 int end;
531 int (*func)();
532 {
533 register struct text *textp;
534 register int l;
535 int rstat;
536 int rbegin;
537 DBG2(8, "applyOnSpaced (%d-%d)\n", begin, end);
538 rstat = S_START;
539 rbegin = begin;
540 for (l = begin; l <= end; l++) {
541 textp = texts[l];
542 switch (rstat) {
543 case S_START:
544 if (l >= end)
545 break;
546 else if (!textp->blank
547 && textp->block == NULL) {
548 rbegin = l;
549 rstat = S_SPACED;
550 }
551 break;
552 case S_SPACED:
553 if (l >= end
554 || textp->blank
555 || textp->block != NULL) {
556 (*func)(rbegin, l<end?l:end);
557 rstat = S_START;
558 }
559 break;
560 default:
561 fprintf(stderr, "PANIC(undefined status)%d\n", rstat);
562 exit(2);
563 }
564 }
565 }
566 /*
567 * join blocks
568 */
joinBlocks(begin,end,tbType)569 joinBlocks(begin, end, tbType)
570 int begin;
571 int end;
572 int tbType;
573 {
574 struct textBlock *tbp;
575 struct textBlock *nextTbp;
576 int l, l2;
577 for (l = begin; l < end; l++) {
578 if ((tbp = texts[l]->block) && !tbp->hinted
579 && tbp->type == tbType) {
580 nextTbp = texts[tbp->rend]->block;
581 if (nextTbp
582 && !nextTbp->hinted && nextTbp->type == tbType){
583 /* join it */
584 DBG4(3, "Join [%d,%d]-[%d,%d]\n",
585 tbp->rbegin, tbp->rend,
586 nextTbp->rbegin, nextTbp->rend);
587 for (l2 = tbp->rend;
588 l2 < nextTbp->rend; l2++)
589 texts[l2]->block = tbp;
590 tbp->rend = nextTbp->rend;
591 free((char *)nextTbp);
592 }
593 }
594 }
595 }
596