1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1995, by Sun Microsystems, Inc.
23 * All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include "big5_cns11643.h" /* Big-5 to CNS 11643 mapping table */
30 #include "gb18030_big5.h" /* GBK to Big-5 mapping table */
31
32 #ifdef DEBUG
33 #include <sys/fcntl.h>
34 #include <sys/stat.h>
35 #endif
36
37 #define MSB 0x80 /* most significant bit */
38 #define MBYTE 0x8e /* multi-byte (4 byte character) */
39 #define PMASK 0xa0 /* plane number mask */
40 #define ONEBYTE 0xff /* right most byte */
41 #define MSB_OFF 0x7f /* mask off MSB */
42
43 #define SI 0x0f /* shift in */
44 #define SO 0x0e /* shift out */
45 #define SS2 0x4e /* SS2 shift out */
46 #define SS3 0x4f /* ss3 shift out, used so far */
47 #define ESC 0x1b /* escape */
48
49 #define gbk4_2nd_byte(v) ( (v) >= 0x30 && (v) <= 0x39 )
50 #define gbk4_3rd_byte(v) ( (v) >= 0x81 && (v) <= 0xfe )
51 #define gbk4_4th_byte(v) gbk4_2nd_byte(v)
52
53 /* We use plane 0 for GB2312 */
54
55 static const char plane_char[] = "AGHIJKLMNOPQRSTUV";
56
57 #define GET_PLANEC(i) (plane_char[i])
58
59 #define NON_ID_CHAR_BYTE1 0x21 /* non-identified character */
60 #define NON_ID_CHAR_BYTE2 0x75 /* non-identified character */
61
62 typedef struct _icv_state {
63 unsigned char keepc[2]; /* maximum # byte of Big-5 code */
64 short gstate; /* state machine id (Big-5) */
65 short istate; /* state machine id (ISO) */
66 short plane; /* plane no. */
67 short last_plane; /* last charactor's plane no. */
68 int _errno; /* internal errno */
69 } _iconv_st;
70
71 enum _CSTATE { G0, G1, G2, G3 };
72 enum _ISTATE { IN, OUT };
73
74
75 void get_plane_no_by_big5(_iconv_st * , int * , unsigned long *);
76 int isGB2312Char(_iconv_st * st);
77 int isBIG5Char(_iconv_st * st);
78 int binsearch_gbk_big5(unsigned int gbkcode);
79 int binsearch(unsigned long x, table_t v[], int n);
80 int gb_to_iso(_iconv_st * st, char* buf, int buflen);
81 int isGBK2(_iconv_st * st);
82 int big5_to_iso(_iconv_st * st, int unidx, unsigned long cnscode, char * buf,
83 size_t buflen);
84
85
isGBK2(_iconv_st * st)86 int isGBK2(_iconv_st * st) {
87 unsigned char c0, c1;
88
89 c0 = st->keepc[0] & ONEBYTE;
90 c1 = st->keepc[1] & ONEBYTE;
91 if (c0 >= 0x80 && c0 <= 0xfe && \
92 c1 >= 0x40 && c1 <= 0xfe && \
93 c1 != 0x7f)
94 return 1;
95 st->_errno = EILSEQ;
96 return 0;
97 }
98
99 /*
100 * Open; called from iconv_open()
101 */
_icv_open()102 void * _icv_open() {
103 _iconv_st *st;
104
105 if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) {
106 errno = ENOMEM;
107 return ((void *) -1);
108 }
109
110 st->gstate = G0;
111 st->istate = IN;
112 st->plane = st->last_plane = -1;/* give it an invalid initnumber */
113 st->_errno = 0;
114 return ((void *) st);
115 }
116
117
118 /*
119 * Close; called from iconv_close()
120 */
_icv_close(_iconv_st * st)121 void _icv_close(_iconv_st *st) {
122 if (st == NULL)
123 errno = EBADF;
124 else
125 free(st);
126 }
127
128
129 /*
130 *Actual conversion; called from iconv()
131 */
132 /*=======================================================
133 *
134 * State Machine for interpreting GBK code
135 *
136 *=======================================================
137 *
138 * 3rd C
139 * G2--------> G3
140 * ^ |
141 * 2nd C | 4th C |
142 * 1st C | |
143 * +--------> G0 ----------> G1 |
144 * | ascii | 2nd C | |
145 * ^ v v V
146 * +----<-----+-----<--------+-----<------+
147 *
148 *=======================================================*/
149 /*
150 * GBK2 encoding range:
151 * High byte: 0x81 - 0xFE
152 * Low byte: 0x40 - 0x7E, 0x80 - 0xFE
153 *
154 * GBK4 encoding range:
155 * The 1st byte: 0x81 - 0xFE
156 * The 2nd byte: 0x30 - 0x39
157 * The 3rd byte: 0x81 - 0xFE
158 * The 4th byte: 0x30 - 0x39
159 *
160 * We divide the GBK charset into three parts:
161 * GB2312:
162 * High byte: 0xb0 - 0xfe
163 * Low byte: 0xa1 - 0xfe
164 * Exclusive: 0xd7fa - 0xd8fe
165 * Big5:
166 * Plane #1: 0xA140 - 0xC8FE
167 * Plane #2: 0xC940 - 0xFEFE
168 * Other:
169 * Unknow Chinese charactors
170 */
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)171 size_t _icv_iconv( _iconv_st *st,
172 char **inbuf,
173 size_t *inbytesleft,
174 char **outbuf,
175 size_t *outbytesleft) {
176 int n, unidx;
177 unsigned long cnscode;
178 if (st == NULL) {
179 errno = EBADF;
180 return ((size_t) -1);
181 }
182
183 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
184 if (st->gstate == G1) {
185 if (outbytesleft && *outbytesleft >= 1 &&
186 outbuf && *outbuf) {
187 **outbuf = SI;
188 (*outbuf) ++;
189 (*outbytesleft) --;
190 } else {
191 errno = E2BIG;
192 return ((size_t)-1);
193 }
194 }
195 st->gstate = G0;
196 st->istate = IN;
197 st->plane = 0;
198 st->last_plane = 0;
199 st->_errno = 0;
200 return ((size_t) 0);
201 }
202
203 errno = st->_errno = 0; /* reset internal & external errno */
204
205 /*
206 * Automatic machine starts.
207 */
208 while (*inbytesleft > 0 && *outbytesleft > 0) {
209 switch (st->gstate) {
210 case G0: /* beginning with ASCII*/
211 if (**inbuf & MSB) {
212 st->keepc[0] = (**inbuf);
213 st->gstate = G1;
214 } else { /* ASCII */
215 if (st->istate == OUT) {
216 st->gstate = G0;
217 st->istate = IN;
218 if (*outbytesleft >= 2) {
219 **outbuf = SI;
220 (*outbuf)++;
221 (*outbytesleft)--;
222 } else {
223 errno = st->_errno = E2BIG;
224 return(size_t)(-1);
225 }
226 st->last_plane = st->plane;
227 }
228 **outbuf = **inbuf;
229 (*outbuf)++;
230 (*outbytesleft)--;
231 }
232 break;
233 case G1: /* Chinese characters: 2nd byte */
234 st->keepc[1] = (**inbuf);
235 if ( gbk4_2nd_byte((unsigned char)**inbuf) ) {
236 st->gstate = G2;
237 } else if (!isGBK2(st)) {
238 errno = st->_errno;
239 return (size_t)-1;
240 } else if (isGB2312Char(st)) {
241 st->plane = 0; /* 0 is for GB2312 */
242 if (st->last_plane == -1 || \
243 st->plane != st->last_plane) {
244 if (*outbytesleft < 5) {
245 errno = st->_errno = E2BIG;
246 return (size_t)-1;
247 }
248 **outbuf = ESC;
249 *(*outbuf + 1) = '$';
250 *(*outbuf+2) = ')';
251 *(*outbuf+3) = 'A';
252 *(*outbuf+4) = SO;
253 (*outbuf) += 5;
254 (*outbytesleft) -= 5;
255 st->last_plane = st->plane;
256 } else if (st->istate == IN) {
257 **outbuf = SO;
258 (*outbuf) += 1;
259 (*outbytesleft) -= 1;
260 }
261 n = gb_to_iso(st, *outbuf, *outbytesleft);
262 if (n > 0) {
263 (*outbuf) += n;
264 (*outbytesleft) -= n;
265 } else {
266 errno = st->_errno;
267 return (size_t)-1;
268 }
269 st->istate = OUT;
270 st->gstate = G0;
271 } else if (isBIG5Char(st)) {
272 get_plane_no_by_big5(st, &unidx, &cnscode);
273 if (unidx < 0) { /* legal Big-5; illegal CNS */
274 goto nonindentify;
275 }
276
277 if (st->last_plane != st->plane) {
278 switch (st->plane) {
279 case 1:
280 if (*outbytesleft < 5) {
281 st->_errno = errno = E2BIG;
282 return (size_t)-1;
283 }
284 **outbuf = ESC;
285 *(*outbuf + 1) = '$';
286 *(*outbuf + 2) = ')';
287 *(*outbuf + 3) = 'G';
288 *(*outbuf + 4) = SO;
289 (*outbuf) += 5;
290 (*outbytesleft) -= 5;
291 break;
292 case 2:
293 if (*outbytesleft < 6) {
294 errno = st->_errno = E2BIG;
295 return (size_t)-1;
296 }
297 **outbuf = ESC;
298 *(*outbuf + 1) = '$';
299 *(*outbuf + 2) = '*';
300 *(*outbuf + 3) = 'H';
301 *(*outbuf + 4) = ESC;
302 *(*outbuf + 5) = SS2;
303 (*outbuf) += 6;
304 (*outbytesleft) -= 6;
305 break;
306 case 3:
307 case 4:
308 case 5:
309 case 6:
310 case 7:
311 case 8:
312 case 9:
313 if (*outbytesleft < 6) {
314 errno = st->_errno = E2BIG;
315 return (size_t)-1;
316 }
317 **outbuf = ESC;
318 *(*outbuf + 1) = '$';
319 *(*outbuf + 2) = '+';
320 *(*outbuf + 3) = GET_PLANEC(st->plane);
321 *(*outbuf + 4) = ESC;
322 *(*outbuf + 5) = SS3;
323 (*outbuf) += 6;
324 (*outbytesleft) -= 6;
325 break;
326 default:
327 errno = st->_errno = EILSEQ;
328 return (size_t)-1;
329 }
330 st->last_plane = st->plane;
331 } else if (st->istate == IN) {
332 switch (st->plane) {
333 case 1:
334 **outbuf = SO;
335 (*outbuf) ++;
336 (*outbytesleft)--;
337 break;
338 case 2:
339 if (*outbytesleft >= 2) {
340 **outbuf = ESC;
341 *(*outbuf + 1) = SS2;
342 (*outbuf) += 2;
343 (*outbytesleft) -= 2;
344 } else {
345 errno = st->_errno = E2BIG;
346 return (size_t)-1;
347 }
348 break;
349 case 3:
350 case 4:
351 case 5:
352 case 6:
353 case 7:
354 case 8:
355 case 9:
356 if (*outbytesleft >= 2) {
357 **outbuf = ESC;
358 *(*outbuf + 1) = SS3;
359 (*outbuf) += 2;
360 (*outbytesleft) -= 2;
361 } else {
362 errno = st->_errno = E2BIG;
363 return (size_t)-1;
364 }
365 break;
366 default:
367 break;
368 } /* end of switch */
369 }
370 n = big5_to_iso(st, unidx, cnscode,
371 *outbuf, *outbytesleft);
372 if (n > 0) {
373 (*outbuf) += n;
374 (*outbytesleft) -= n;
375 } else {
376 errno = st->_errno;
377 return(size_t)(-1);
378 }
379 st->istate = OUT;
380 st->gstate = G0;
381 } else { /* Neither GB2312 nor Big5 */
382 nonindentify: st->plane = 0;
383 if (st->plane != st->last_plane) {
384 if (*outbytesleft >= 7) {
385 **outbuf = ESC;
386 *(*outbuf + 1) = '$';
387 *(*outbuf + 2) = ')';
388 *(*outbuf + 3) = 'A';
389 *(*outbuf + 4) = SO;
390 (*outbuf) += 5;
391 (*outbytesleft) -= 5;
392 } else {
393 st->_errno = errno = E2BIG;
394 return (size_t)-1;
395 }
396 st->last_plane = st->plane;
397 } else if (st->istate == IN) {
398 if (*outbytesleft >= 3) {
399 **outbuf = SO;
400 (*outbuf)++;
401 (*outbytesleft)--;
402 } else {
403 st->_errno = errno = E2BIG;
404 return (size_t)-1;
405 }
406 }
407
408 if ( *outbytesleft < 2) {
409 errno = st->_errno = E2BIG;
410 return (size_t)-1;
411 }
412 **outbuf = NON_ID_CHAR_BYTE1;
413 *(*outbuf + 1) = NON_ID_CHAR_BYTE2;
414 (*outbuf) += 2;
415 (*outbytesleft) -= 2;
416 st->istate = OUT;
417 st->gstate = G0;
418 st->_errno = 0;
419 }
420 break;
421 case G2:
422 if ( gbk4_3rd_byte((unsigned char)**inbuf) ) {
423 st->gstate = G3;
424 } else {
425 errno = st->_errno = EILSEQ;
426 return (size_t)-1;
427 }
428 break;
429 case G3:
430 if ( gbk4_4th_byte((unsigned char)**inbuf) ) {
431 st->plane = 0;
432 if ( st->plane != st->last_plane ) {
433 if (*outbytesleft >= 7) {
434 **outbuf = ESC;
435 *(*outbuf + 1) = '$';
436 *(*outbuf + 2) = ')';
437 *(*outbuf + 3) = 'A';
438 *(*outbuf + 4) = SO;
439 (*outbuf) += 5;
440 (*outbytesleft) -= 5;
441 } else {
442 st->_errno = errno = E2BIG;
443 return (size_t)-1;
444 }
445 st->last_plane = st->plane;
446 } else if (st->istate == IN) {
447 if (*outbytesleft >= 3) {
448 **outbuf = SO;
449 (*outbuf)++;
450 (*outbytesleft)--;
451 } else {
452 st->_errno = errno = E2BIG;
453 return (size_t)-1;
454 }
455 }
456
457 if ( *outbytesleft < 2) {
458 errno = st->_errno = E2BIG;
459 return (size_t) -1;
460 }
461
462 **outbuf = NON_ID_CHAR_BYTE1;
463 *(*outbuf + 1) = NON_ID_CHAR_BYTE2;
464 (*outbuf) += 2;
465 (*outbytesleft) -= 2;
466 st->istate = OUT;
467 st->gstate = G0;
468 st->_errno = 0;
469 } else {
470 errno = st->_errno = EILSEQ;
471 return (size_t)-1;
472 }
473 break;
474 default: /* should never come here */
475 st->_errno = errno = EILSEQ;
476 st->istate = IN;
477 st->gstate = G0; /* reset state */
478 break;
479 }
480
481 (*inbuf)++;
482 (*inbytesleft)--;
483
484 if (st->_errno) {
485 break;
486 }
487 if (errno)
488 return (size_t)(-1);
489 }
490
491 if (*inbytesleft == 0 && st->gstate != G0 ) {
492 errno = EINVAL;
493 return (size_t)-1;
494 }
495
496 if (*inbytesleft > 0 && *outbytesleft == 0) {
497 st->_errno = errno = E2BIG;
498 return (size_t)(-1);
499 }
500 return (size_t)(*inbytesleft);
501 }
502
503
isGB2312Char(_iconv_st * st)504 int isGB2312Char(_iconv_st * st) {
505 unsigned char buf1 = (unsigned char) (st->keepc[0] & ONEBYTE);
506 unsigned char buf2 = (unsigned char) (st->keepc[1] & ONEBYTE);
507
508 if (buf2 >= 0xA1 && buf2 <= 0xFE) {
509 if ((buf1 >= 0xA1 && buf1 <= 0xA9) || \
510 (buf1 >= 0xB0 && buf1 <= 0xF7))
511 return 1;
512 }
513 return 0;
514 }
515
isBIG5Char(_iconv_st * st)516 int isBIG5Char(_iconv_st * st) {
517 unsigned int gbkcode = \
518 (unsigned int) (((st->keepc[0] & ONEBYTE) << 8) | \
519 (st->keepc[1] & ONEBYTE));
520 unsigned int big5code;
521 int idx;
522
523 if (gbkcode < gbk_big5_tab[0].key || \
524 gbkcode > gbk_big5_tab[BIG5MAX-1].key) {
525 return 0;
526 }
527 idx = binsearch_gbk_big5(gbkcode);
528 if (idx < 0)
529 return 0;
530 else {
531 big5code = gbk_big5_tab[idx].value;
532 st->keepc[0] = (unsigned char)((big5code >> 8) & ONEBYTE);
533 st->keepc[1] = (unsigned char)(big5code & ONEBYTE);
534 return 1;
535 }
536 }
537
538 /*
539 * Test whether inbuf is a valid character for 2nd byte Big-5 code
540 * Return: = 0 - valid Big-5 2nd byte
541 * = 1 - invalid Big-5 2nd byte
542 */
big5_2nd_byte(inbuf)543 int big5_2nd_byte(inbuf)
544 char inbuf;
545 {
546 unsigned char buf = (unsigned char) (inbuf & ONEBYTE);
547
548 if ((buf >= 0x40) && (buf <= 0x7E))
549 return (0);
550 if ((buf >= 0xA1) && (buf <= 0xFE))
551 return (0);
552 return(1);
553 }
554
555
556 /*
557 * Get plane number by Big-5 code; i.e. plane #1 returns 1, #2 returns 2, etc.
558 * Returns -1 on error conditions
559 *
560 * Since binary search of the Big-5 to CNS table is necessary, might as well
561 * return index and CNS code matching to the unicode.
562 */
get_plane_no_by_big5(_iconv_st * st,int * unidx,unsigned long * cnscode)563 void get_plane_no_by_big5(_iconv_st * st,
564 int * unidx,
565 unsigned long * cnscode) {
566 int ret;
567 unsigned long big5code;
568
569 big5code = (unsigned long) ((st->keepc[0] & ONEBYTE) << 8) + \
570 (st->keepc[1] & ONEBYTE);
571 *unidx = binsearch(big5code, big5_cns_tab, MAX_BIG5_NUM);
572 if ((*unidx) >= 0)
573 *cnscode = big5_cns_tab[*unidx].value;
574 else {
575 return; /* match from Big-5 to CNS not found */
576 }
577 ret = (int) (*cnscode >> 16);
578 switch (ret) {
579 case 0x21: /* 0x8EA1 - G */
580 case 0x22: /* 0x8EA2 - H */
581 case 0x23: /* 0x8EA3 - I */
582 case 0x24: /* 0x8EA4 - J */
583 case 0x25: /* 0x8EA5 - K */
584 case 0x26: /* 0x8EA6 - L */
585 case 0x27: /* 0x8EA7 - M */
586 case 0x28: /* 0x8EA8 - N */
587 case 0x29: /* 0x8EA9 - O */
588 case 0x2a: /* 0x8EAA - P */
589 case 0x2b: /* 0x8EAB - Q */
590 case 0x2c: /* 0x8EAC - R */
591 case 0x2d: /* 0x8EAD - S */
592 case 0x2f: /* 0x8EAF - U */
593 case 0x30: /* 0x8EB0 - V */
594 st->plane = ret - 0x20; /* so that we can use GET_PLANEC() */
595 break;
596 case 0x2e: /* 0x8EAE - T */
597 st->plane = 3; /* CNS 11643-1992 */
598 break;
599 default:
600 st->_errno = EILSEQ;
601 return;
602 }
603 st->_errno = 0;
604 }
605
606
607 /*
608 * Big-5 code --> ISO 2022-7
609 * Return: > 0 - converted with enough space in output buffer
610 * = 0 - no space in outbuf
611 */
big5_to_iso(_iconv_st * st,int unidx,unsigned long cnscode,char * buf,size_t buflen)612 int big5_to_iso(_iconv_st * st, int unidx,
613 unsigned long cnscode,
614 char * buf, size_t buflen) {
615 unsigned long val; /* CNS 11643 value */
616
617 if (buflen < 2) {
618 st->_errno = E2BIG;
619 return 0;
620 }
621
622 if (unidx < 0) { /* no match from UTF8 to CNS 11643 */
623 st->_errno = EILSEQ;
624 return 0;
625 } else {
626 val = cnscode & 0xffff;
627 *buf = (unsigned char)((val & 0xff00) >> 8);
628 *(buf+1) = (unsigned char)(val & 0xff);
629 }
630
631 return(2);
632 }
633
634
635 /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
binsearch(unsigned long x,table_t v[],int n)636 int binsearch(unsigned long x, table_t v[], int n) {
637 int low, high, mid;
638
639 low = 0;
640 high = n - 1;
641 while (low <= high) {
642 mid = (low + high) / 2;
643 if (x < v[mid].key)
644 high = mid - 1;
645 else if (x > v[mid].key)
646 low = mid + 1;
647 else /* found match */
648 return mid;
649 }
650 return (-1); /* no match */
651 }
652
653 /* binsearch_gbk_big5: find x in v[0] <= v[1] <= ... <= v[n-1] */
binsearch_gbk_big5(unsigned int c)654 int binsearch_gbk_big5(unsigned int c) {
655 int low, high, mid;
656 long gbkcode = (long)(c & 0xFFFF);
657
658 low = 0;
659 high = BIG5MAX - 1;
660 while (low <= high) {
661 mid = (low + high) / 2;
662 if (gbkcode < gbk_big5_tab[mid].key)
663 high = mid - 1;
664 else if (gbkcode > gbk_big5_tab[mid].key)
665 low = mid + 1;
666 else /* found match */
667 return mid;
668 }
669 return (-1); /* no match */
670 }
671
672 /*
673 * return: > 0 - converted with enough space
674 * = 0 - no space in outbuf
675 */
gb_to_iso(_iconv_st * st,char * buf,int buflen)676 int gb_to_iso(_iconv_st * st, char* buf, int buflen) {
677 if ( buflen < 2 ) {
678 st->_errno = E2BIG;
679 return 0;
680 }
681 *buf = st->keepc[0] & MSB_OFF;
682 *(buf+1) = st->keepc[1] & MSB_OFF;
683 return 2;
684 }
685
686 #ifdef DEBUG
main(int argc,char ** argv)687 int main(int argc, char ** argv) {
688 _iconv_st * st;
689 char *inbuf, *outbuf, *in_tmp, *out_tmp;
690 size_t inlen, outlen;
691 int fd, i;
692 struct stat s;
693
694 if (argc < 2) {
695 exit(-1);
696 }
697 if ((fd = open(argv[1], O_RDONLY)) == -1) {
698 perror("open");
699 exit(-2);
700 }
701 if (fstat(fd, &s) == -1) {
702 perror("stat");
703 exit(-2);
704 }
705 inlen = s.st_size;
706 in_tmp = inbuf = (char *)malloc(inlen);
707 out_tmp = outbuf = (char*)malloc((outlen = inlen * 3));
708 if (!inbuf || !outbuf) {
709 perror("malloc");
710 exit(-1);
711 }
712 if (read(fd, inbuf, inlen) != inlen) {
713 perror("read");
714 exit(-4);
715 }
716 st = _icv_open();
717 if (st == (_iconv_st *) -1) {
718 perror("_icv_open");
719 exit(-3);
720 }
721 if (_icv_iconv(st, &inbuf, &inlen, &outbuf, &outlen))
722 perror("ERROR");
723 fprintf(stderr, "%d bytes left\n", outlen);
724 if (write(1, out_tmp, s.st_size * 5 - outlen) == -1) {
725 perror("write");
726 exit(-5);
727 }
728 free(in_tmp);
729 free(out_tmp);
730 close(fd);
731 _icv_close(st);
732 }
733 #endif
734