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 &blank;
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 &blank;
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