dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / sgs / m4 / common / m4.c
blob1d6f04c3d331b117693d844a1a0d915cd81c523a
1 /*
2 * CDDL HEADER START
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.
8 * You can obtain a copy of the license at usr/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.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/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]
19 * CDDL HEADER END
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright (c) 2011 Gary Mills
30 /* Copyright (c) 1988 AT&T */
31 /* All Rights Reserved */
33 #include <signal.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include "m4.h"
39 #define match(c, s) (c == *s && (!s[1] || inpmatch(s+1)))
41 static char tmp_name[] = "/tmp/m4aXXXXX";
42 static wchar_t prev_char;
43 static int mb_cur_max;
45 static void getflags(int *, char ***, int *);
46 static void initalloc(void);
47 static void expand(wchar_t **, int);
48 static void lnsync(FILE *);
49 static void fpath(FILE *);
50 static void puttok(wchar_t *);
51 static void error3(void);
52 static wchar_t itochr(int);
53 /*LINTED: E_STATIC_UNUSED*/
54 static wchar_t *chkbltin(wchar_t *);
55 static wchar_t *inpmatch(wchar_t *);
56 static void chkspace(char **, int *, char ***);
57 static void catchsig(int);
58 static FILE *m4open(char ***, char *, int *);
59 static void showwrap(void);
60 static void sputchr(wchar_t, FILE *);
61 static void putchr(wchar_t);
62 static void *xcalloc(size_t, size_t);
63 static wint_t myfgetwc(FILE *, int);
64 static wint_t myfputwc(wchar_t, FILE *);
65 static int myfeof(int);
67 int
68 main(int argc, char **argv)
70 wchar_t t;
71 int i, opt_end = 0;
72 int sigs[] = {SIGHUP, SIGINT, SIGPIPE, 0};
74 ifile[0] = stdin;
75 ofile[0] = stdout;
76 cf = stdout;
78 for (i = 0; sigs[i]; ++i) {
79 if (signal(sigs[i], SIG_IGN) != SIG_IGN)
80 (void) signal(sigs[i], catchsig);
82 tempfile = mktemp(tmp_name);
83 (void) close(creat(tempfile, 0));
85 (void) setlocale(LC_ALL, "");
87 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
88 #define TEXT_DOMAIN "SYS_TEST"
89 #endif
90 (void) textdomain(TEXT_DOMAIN);
92 if ((mb_cur_max = MB_CUR_MAX) > 1)
93 wide = 1;
95 procnam = argv[0];
96 getflags(&argc, &argv, &opt_end);
97 initalloc();
99 setfname("-");
100 if (argc > 1) {
101 --argc;
102 ++argv;
103 if (strcmp(argv[0], "-")) {
104 ifile[ifx] = m4open(&argv, "r", &argc);
105 setfname(argv[0]);
109 for (;;) {
110 token[0] = t = getchr();
111 token[1] = EOS;
113 if (t == WEOF) {
114 if (ifx > 0) {
115 (void) fclose(ifile[ifx]);
116 ipflr = ipstk[--ifx];
117 continue;
120 getflags(&argc, &argv, &opt_end);
122 if (argc <= 1)
124 * If dowrap() has been called, the m4wrap
125 * macro has been processed, and a linked
126 * list of m4wrap strings has been created.
127 * The list starts at wrapstart.
129 if (wrapstart) {
131 * Now that EOF has been processed,
132 * display the m4wrap strings.
134 showwrap();
135 continue;
136 } else
137 break;
138 --argc;
139 ++argv;
141 if (ifile[ifx] != stdin)
142 (void) fclose(ifile[ifx]);
144 if (strcmp(argv[0], "-"))
145 ifile[ifx] = m4open(&argv, "r", &argc);
146 else
147 ifile[ifx] = stdin;
149 setfname(argv[0]);
150 continue;
153 if (is_alpha(t) || t == '_') {
154 wchar_t *tp = token+1;
155 int tlim = toksize;
156 struct nlist *macadd; /* temp variable */
158 while ((*tp = getchr()) != WEOF &&
159 (is_alnum(*tp) || *tp == '_')) {
160 tp++;
161 if (--tlim <= 0)
162 error2(gettext(
163 "more than %d chars in word"),
164 toksize);
166 putbak(*tp);
167 *tp = EOS;
169 macadd = lookup(token);
170 *Ap = (wchar_t *)macadd;
171 if (macadd->def) {
172 if ((wchar_t *)(++Ap) >= astklm) {
173 --Ap;
174 error2(gettext(
175 "more than %d items on "
176 "argument stack"),
177 stksize);
180 if (Cp++ == NULL)
181 Cp = callst;
183 Cp->argp = Ap;
184 *Ap++ = op;
185 puttok(token);
186 stkchr(EOS);
187 t = getchr();
188 putbak(t);
190 if (t != '(')
191 pbstr(L"()");
192 else /* try to fix arg count */
193 *Ap++ = op;
195 Cp->plev = 0;
196 } else {
197 puttok(token);
199 } else if (match(t, lquote)) {
200 int qlev = 1;
202 for (;;) {
203 token[0] = t = getchr();
204 token[1] = EOS;
206 if (match(t, rquote)) {
207 if (--qlev > 0)
208 puttok(token);
209 else
210 break;
211 } else if (match(t, lquote)) {
212 ++qlev;
213 puttok(token);
214 } else {
215 if (t == WEOF)
216 error(gettext(
217 "EOF in quote"));
218 putchr(t);
221 } else if (match(t, lcom) &&
222 ((lcom[0] != L'#' || lcom[1] != L'\0') ||
223 prev_char != '$')) {
226 * Don't expand commented macro (between lcom and
227 * rcom).
228 * What we know so far is that we have found the
229 * left comment char (lcom).
230 * Make sure we haven't found '#' (lcom) immediately
231 * preceded by '$' because we want to expand "$#".
234 puttok(token);
235 for (;;) {
236 token[0] = t = getchr();
237 token[1] = EOS;
238 if (match(t, rcom)) {
239 puttok(token);
240 break;
241 } else {
242 if (t == WEOF)
243 error(gettext(
244 "EOF in comment"));
245 putchr(t);
248 } else if (Cp == NULL) {
249 putchr(t);
250 } else if (t == '(') {
251 if (Cp->plev)
252 stkchr(t);
253 else {
254 /* skip white before arg */
255 while ((t = getchr()) != WEOF && is_space(t))
258 putbak(t);
261 ++Cp->plev;
262 } else if (t == ')') {
263 --Cp->plev;
265 if (Cp->plev == 0) {
266 stkchr(EOS);
267 expand(Cp->argp, Ap-Cp->argp-1);
268 op = *Cp->argp;
269 Ap = Cp->argp-1;
271 if (--Cp < callst)
272 Cp = NULL;
273 } else
274 stkchr(t);
275 } else if (t == ',' && Cp->plev <= 1) {
276 stkchr(EOS);
277 *Ap = op;
279 if ((wchar_t *)(++Ap) >= astklm) {
280 --Ap;
281 error2(gettext(
282 "more than %d items on argument stack"),
283 stksize);
286 while ((t = getchr()) != WEOF && is_space(t))
289 putbak(t);
290 } else {
291 stkchr(t);
295 if (Cp != NULL)
296 error(gettext(
297 "EOF in argument list"));
299 delexit(exitstat, 1);
300 return (0);
303 static wchar_t *
304 inpmatch(wchar_t *s)
306 wchar_t *tp = token+1;
308 while (*s) {
309 *tp = getchr();
311 if (*tp++ != *s++) {
312 *tp = EOS;
313 pbstr(token+1);
314 return (0);
318 *tp = EOS;
319 return (token);
322 static void
323 getflags(int *xargc, char ***xargv, int *option_end)
325 char *arg;
326 char *t;
327 wchar_t *s[3];
329 while (*xargc > 1) {
330 arg = (*xargv)[1]; /* point arg to current argument */
333 * This argument is not an option if it equals "-" or if
334 * "--" has already been parsed.
336 if (arg[0] != '-' || arg[1] == EOS || *option_end)
337 break;
338 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') {
339 *option_end = 1;
340 } else {
341 switch (arg[1]) {
342 case 'B':
343 chkspace(&arg, xargc, xargv);
344 bufsize = atoi(&arg[2]);
345 if (bufsize <= 0) {
346 bufsize = DEF_BUFSIZE;
348 break;
349 case 'D':
350 initalloc();
351 chkspace(&arg, xargc, xargv);
352 for (t = &arg[2]; *t; t++) {
353 if (*t == '=') {
354 *t++ = EOS;
355 break;
358 s[1] = str2wstr(&arg[2], 1);
359 s[2] = str2wstr(t, 1);
360 dodef(&s[0], 2);
361 free(s[1]);
362 free(s[2]);
363 break;
364 case 'H':
365 chkspace(&arg, xargc, xargv);
366 hshsize = atoi(&arg[2]);
367 if (hshsize <= 0) {
368 hshsize = DEF_HSHSIZE;
370 break;
371 case 'S':
372 chkspace(&arg, xargc, xargv);
373 stksize = atoi(&arg[2]);
374 if (stksize <= 0) {
375 stksize = DEF_STKSIZE;
377 break;
378 case 'T':
379 chkspace(&arg, xargc, xargv);
380 toksize = atoi(&arg[2]);
381 if (toksize <= 0) {
382 toksize = DEF_TOKSIZE;
384 break;
385 case 'U':
386 initalloc();
387 chkspace(&arg, xargc, xargv);
388 s[1] = str2wstr(&arg[2], 1);
389 doundef(&s[0], 1);
390 free(s[1]);
391 break;
392 case 'e':
393 setbuf(stdout, NULL);
394 (void) signal(SIGINT, SIG_IGN);
395 break;
396 case 's':
397 /* turn on line sync */
398 sflag = 1;
399 break;
400 default:
401 (void) fprintf(stderr,
402 gettext("%s: bad option: %s\n"),
403 procnam, arg);
404 delexit(NOT_OK, 0);
406 } /* end else not "--" */
408 (*xargv)++;
409 --(*xargc);
410 } /* end while options to process */
414 * Function: chkspace
416 * If there is a space between the option and its argument,
417 * adjust argptr so that &arg[2] will point to beginning of the option argument.
418 * This will ensure that processing in getflags() will work, because &arg[2]
419 * will point to the beginning of the option argument whether or not we have
420 * a space between the option and its argument. If there is a space between
421 * the option and its argument, also adjust xargv and xargc because we are
422 * processing the next argument.
424 static void
425 chkspace(char **argptr, int *xargc, char ***xargv)
427 if ((*argptr)[2] == EOS) {
428 /* there is a space between the option and its argument */
429 (*xargv)++; /* look at the next argument */
430 --(*xargc);
432 * Adjust argptr if the option is followed by an
433 * option argument.
435 if (*xargc > 1) {
436 *argptr = (*xargv)[1];
437 /* point &arg[2] to beginning of option argument */
438 *argptr -= 2;
443 static void
444 initalloc(void)
446 static int done = 0;
447 int t;
449 if (done++)
450 return;
452 hshtab = xcalloc(hshsize, sizeof (struct nlist *));
453 callst = xcalloc(stksize/3+1, sizeof (struct call));
454 Ap = argstk = xcalloc(stksize+3, sizeof (wchar_t *));
455 ipstk[0] = ipflr = ip = ibuf = xcalloc(bufsize+1, sizeof (wchar_t));
456 op = obuf = xcalloc(bufsize+1, sizeof (wchar_t));
457 token = xcalloc(toksize+1, sizeof (wchar_t));
459 astklm = (wchar_t *)(&argstk[stksize]);
460 ibuflm = &ibuf[bufsize];
461 obuflm = &obuf[bufsize];
462 toklm = &token[toksize];
464 for (t = 0; barray[t].bname; ++t) {
465 wchar_t p[2] = {0, EOS};
467 p[0] = builtin(t);
468 install(barray[t].bname, p, NOPUSH);
470 install(L"unix", nullstr, NOPUSH);
473 void
474 install(wchar_t *nam, wchar_t *val, int mode)
476 struct nlist *np;
477 wchar_t *cp;
478 int l;
480 if (mode == PUSH)
481 (void) lookup(nam); /* lookup sets hshval */
482 else
483 while (undef(nam)) /* undef calls lookup */
486 np = xcalloc(1, sizeof (*np));
487 np->name = wstrdup(nam);
488 np->next = hshtab[hshval];
489 hshtab[hshval] = np;
491 cp = xcalloc((l = wcslen(val))+1, sizeof (*val));
492 np->def = cp;
493 cp = &cp[l];
495 while (*val)
496 *--cp = *val++;
499 struct nlist *
500 lookup(wchar_t *str)
502 wchar_t *s1;
503 struct nlist *np;
504 static struct nlist nodef;
506 s1 = str;
508 for (hshval = 0; *s1; )
509 hshval += *s1++;
511 hshval %= hshsize;
513 for (np = hshtab[hshval]; np != NULL; np = np->next) {
514 if (*str == *np->name && wcscmp(str, np->name) == 0)
515 return (np);
517 return (&nodef);
520 static void
521 expand(wchar_t **a1, int c)
523 wchar_t *dp;
524 struct nlist *sp;
526 sp = (struct nlist *)a1[-1];
528 if (sp->tflag || trace) {
529 int i;
531 (void) fprintf(stderr,
532 "Trace(%d): %ws", Cp-callst, a1[0]);
534 if (c > 0) {
535 (void) fprintf(stderr, "(%ws", chkbltin(a1[1]));
536 for (i = 2; i <= c; ++i)
537 (void) fprintf(stderr, ",%ws", chkbltin(a1[i]));
538 (void) fprintf(stderr, ")");
540 (void) fprintf(stderr, "\n");
543 dp = sp->def;
545 for (; *dp; ++dp) {
546 if (is_builtin(*dp)) {
547 (*barray[builtin_idx(*dp)].bfunc)(a1, c);
548 } else if (dp[1] == '$') {
549 if (is_digit(*dp)) {
550 int n;
551 if ((n = *dp-'0') <= c)
552 pbstr(a1[n]);
553 ++dp;
554 } else if (*dp == '#') {
555 pbnum((long)c);
556 ++dp;
557 } else if (*dp == '*' || *dp == '@') {
558 int i = c;
559 wchar_t **a = a1;
561 if (i > 0)
562 for (;;) {
563 if (*dp == '@')
564 pbstr(rquote);
566 pbstr(a[i--]);
568 if (*dp == '@')
569 pbstr(lquote);
571 if (i <= 0)
572 break;
574 pbstr(L",");
576 ++dp;
577 } else
578 putbak(*dp);
579 } else
580 putbak(*dp);
584 void
585 setfname(char *s)
587 free(fname[ifx]);
588 if ((fname[ifx] = strdup(s)) == NULL)
589 error(gettext("out of storage"));
590 fline[ifx] = 1;
591 nflag = 1;
592 lnsync(stdout);
595 static void
596 lnsync(FILE *iop)
598 static int cline = 0;
599 static int cfile = 0;
601 if (!sflag || iop != stdout)
602 return;
604 if (nflag || ifx != cfile) {
605 nflag = 0;
606 cfile = ifx;
607 (void) fprintf(iop, "#line %d \"", cline = fline[ifx]);
608 fpath(iop);
609 (void) fprintf(iop, "\"\n");
610 } else if (++cline != fline[ifx])
611 (void) fprintf(iop, "#line %d\n", cline = fline[ifx]);
614 static void
615 fpath(FILE *iop)
617 int i;
619 if (fname[0] == NULL)
620 return;
622 (void) fprintf(iop, "%s", fname[0]);
624 for (i = 1; i <= ifx; ++i)
625 (void) fprintf(iop, ":%s", fname[i]);
628 /* ARGSUSED */
629 static void
630 catchsig(int i)
632 (void) signal(SIGHUP, SIG_IGN);
633 (void) signal(SIGINT, SIG_IGN);
634 delexit(NOT_OK, 0);
637 void
638 delexit(int code, int flushio)
640 int i;
642 cf = stdout;
645 * if (ofx != 0) {
646 * ofx = 0;
647 * code = NOT_OK;
650 ofx = 0; /* ensure that everything comes out */
651 for (i = 1; i < 10; i++)
652 undiv(i, code);
654 tempfile[7] = 'a';
655 (void) unlink(tempfile);
657 /* flush standard I/O buffers, ie: call exit() not _exit() */
658 if (flushio)
659 exit(code);
661 _exit(code);
664 static void
665 puttok(wchar_t *tp)
667 if (Cp) {
668 while (*tp)
669 stkchr(*tp++);
670 } else if (cf) {
671 while (*tp) {
672 sputchr(*tp++, cf);
677 void
678 pbstr(wchar_t *str)
680 wchar_t *p;
682 for (p = str + wcslen(str); --p >= str; )
683 putbak(*p);
686 void
687 undiv(int i, int code)
689 FILE *fp;
690 wint_t c;
692 if (i < 1 || i > 9 || i == ofx || !ofile[i])
693 return;
695 (void) fclose(ofile[i]);
696 tempfile[7] = 'a'+i;
698 if (code == OK && cf) {
699 fp = xfopen(tempfile, "r");
701 if (wide) {
702 while ((c = myfgetwc(fp, -1)) != WEOF)
703 sputchr((wchar_t)c, cf);
704 } else {
705 while ((c = (wint_t)getc(fp)) != WEOF)
706 sputchr((wchar_t)c, cf);
709 (void) fclose(fp);
712 (void) unlink(tempfile);
713 ofile[i] = NULL;
716 void
717 pbnum(long num)
719 pbnbr(num, 10, 1);
722 void
723 pbnbr(long nbr, int base, int len)
725 int neg = 0;
727 if (base <= 0)
728 return;
730 if (nbr < 0)
731 neg = 1;
732 else
733 nbr = -nbr;
735 while (nbr < 0) {
736 int i;
737 if (base > 1) {
738 i = nbr%base;
739 nbr /= base;
740 #if (-3 % 2) != -1
741 while (i > 0) {
742 i -= base;
743 ++nbr;
745 #endif
746 i = -i;
747 } else {
748 i = 1;
749 ++nbr;
751 putbak(itochr(i));
752 --len;
755 while (--len >= 0)
756 putbak('0');
758 if (neg)
759 putbak('-');
762 static wchar_t
763 itochr(int i)
765 if (i > 9)
766 return ((wchar_t)(i-10+'A'));
767 else
768 return ((wchar_t)(i+'0'));
771 long
772 ctol(wchar_t *str)
774 int sign;
775 long num;
777 while (is_space(*str))
778 ++str;
779 num = 0;
780 if (*str == '-') {
781 sign = -1;
782 ++str;
783 } else
784 sign = 1;
785 while (is_digit(*str))
786 num = num*10 + *str++ - '0';
787 return (sign * num);
791 min(int a, int b)
793 if (a > b)
794 return (b);
795 return (a);
798 FILE *
799 xfopen(char *name, char *mode)
801 FILE *fp;
803 if ((fp = fopen(name, mode)) == NULL)
804 errorf(gettext("cannot open file: %s"),
805 strerror(errno));
807 return (fp);
811 * m4open
813 * Continue processing files when unable to open the given file argument.
815 FILE *
816 m4open(char ***argvec, char *mode, int *argcnt)
818 FILE *fp;
819 char *arg;
821 while (*argcnt > 0) {
822 arg = (*argvec)[0]; /* point arg to current file name */
823 if (arg[0] == '-' && arg[1] == EOS)
824 return (stdin);
825 else {
826 if ((fp = fopen(arg, mode)) == NULL) {
827 (void) fprintf(stderr, gettext(
828 "m4: cannot open %s: "), arg);
829 perror("");
830 if (*argcnt == 1) {
831 /* last arg therefore exit */
832 error3();
833 } else {
834 exitstat = 1;
835 (*argvec)++; /* try next arg */
836 (*argcnt)--;
838 } else
839 break;
842 return (fp);
845 void *
846 xmalloc(size_t size)
848 void *ptr;
850 if ((ptr = malloc(size)) == NULL)
851 error(gettext("out of storage"));
852 return (ptr);
855 static void *
856 xcalloc(size_t nbr, size_t size)
858 void *ptr;
860 ptr = xmalloc(nbr * size);
861 (void) memset(ptr, '\0', nbr * size);
862 return (ptr);
865 /* Typical format: "cannot open file: %s" */
866 /* PRINTFLIKE1 */
867 void
868 errorf(char *str, char *serr)
870 char buf[500];
872 (void) snprintf(buf, sizeof (buf), str, serr);
873 error(buf);
876 /* PRINTFLIKE1 */
877 void
878 error2(char *str, int num)
880 char buf[500];
882 (void) snprintf(buf, sizeof (buf), str, num);
883 error(buf);
886 void
887 error(char *str)
889 (void) fprintf(stderr, "\n%s:", procnam);
890 fpath(stderr);
891 (void) fprintf(stderr, ":%d %s\n", fline[ifx], str);
892 error3();
895 static void
896 error3()
898 if (Cp) {
899 struct call *mptr;
901 /* fix limit */
902 *op = EOS;
903 (Cp+1)->argp = Ap+1;
905 for (mptr = callst; mptr <= Cp; ++mptr) {
906 wchar_t **aptr, **lim;
908 aptr = mptr->argp;
909 lim = (mptr+1)->argp-1;
910 if (mptr == callst)
911 (void) fputws(*aptr, stderr);
912 ++aptr;
913 (void) fputs("(", stderr);
914 if (aptr < lim)
915 for (;;) {
916 (void) fputws(*aptr++, stderr);
917 if (aptr >= lim)
918 break;
919 (void) fputs(",", stderr);
922 while (--mptr >= callst)
923 (void) fputs(")", stderr);
925 (void) fputs("\n", stderr);
927 delexit(NOT_OK, 1);
930 static wchar_t *
931 chkbltin(wchar_t *s)
933 static wchar_t buf[24];
935 if (is_builtin(*s)) {
936 (void) swprintf(buf, sizeof (buf)/sizeof (wchar_t), L"<%ls>",
937 barray[builtin_idx(*s)].bname);
938 return (buf);
940 return (s);
943 wchar_t
944 getchr()
946 static wchar_t C;
948 prev_char = C;
949 if (ip > ipflr)
950 return (*--ip);
951 if (wide) {
952 C = (wchar_t)(myfeof(ifx) ? WEOF : myfgetwc(NULL, ifx));
953 } else {
954 C = (wchar_t)(feof(ifile[ifx]) ?
955 WEOF : (wint_t)getc(ifile[ifx]));
957 if (C == '\n')
958 fline[ifx]++;
959 return (C);
963 * showwrap
965 * Loop through the list of m4wrap strings. Call pbstr() so that the
966 * string will be displayed, then delete the list entry and free the memory
967 * allocated for it.
969 static void
970 showwrap()
972 struct Wrap *prev;
974 while (wrapstart) {
975 pbstr(wrapstart->wrapstr);
976 free(wrapstart->wrapstr);
977 prev = wrapstart;
978 wrapstart = wrapstart->nxt;
979 free(prev);
983 static void
984 sputchr(wchar_t c, FILE *f)
986 wint_t ret;
988 if (is_builtin(c))
989 return;
990 if (wide)
991 ret = myfputwc(c, f);
992 else
993 ret = (wint_t)putc((int)c, f);
994 if (ret == WEOF)
995 error(gettext("output error"));
996 if (ret == '\n')
997 lnsync(f);
1000 static void
1001 putchr(wchar_t c)
1003 wint_t ret;
1005 if (Cp)
1006 stkchr(c);
1007 else if (cf) {
1008 if (sflag)
1009 sputchr(c, cf);
1010 else {
1011 if (is_builtin(c))
1012 return;
1013 if (wide)
1014 ret = myfputwc(c, cf);
1015 else
1016 ret = (wint_t)putc((int)c, cf);
1017 if (ret == WEOF) {
1018 error(gettext("output error"));
1024 wchar_t *
1025 wstrdup(wchar_t *p)
1027 size_t len = wcslen(p);
1028 wchar_t *ret;
1030 ret = xmalloc((len + 1) * sizeof (wchar_t));
1031 (void) wcscpy(ret, p);
1032 return (ret);
1036 wstoi(wchar_t *p)
1038 return ((int)wcstol(p, NULL, 10));
1041 char *
1042 wstr2str(wchar_t *from, int alloc)
1044 static char *retbuf;
1045 static size_t bsiz;
1046 char *p, *ret;
1048 if (alloc) {
1049 ret = p = xmalloc(wcslen(from) * mb_cur_max + 1);
1050 } else {
1051 while (bsiz < (wcslen(from) * mb_cur_max + 1)) {
1052 if ((p = realloc(retbuf, bsiz + 256)) == NULL)
1053 error(gettext("out of storage"));
1054 bsiz += 256;
1055 retbuf = p;
1057 ret = p = retbuf;
1060 if (wide) {
1061 while (*from) {
1062 int len;
1064 if (*from & INVALID_CHAR) {
1065 *p = (char)(*from & ~INVALID_CHAR);
1066 len = 1;
1067 } else {
1068 if ((len = wctomb(p, *from)) == -1) {
1069 *p = (char)*from;
1070 len = 1;
1073 p += len;
1074 from++;
1076 } else {
1077 while (*from)
1078 *p++ = (char)*from++;
1080 *p = '\0';
1082 return (ret);
1085 wchar_t *
1086 str2wstr(char *from, int alloc)
1088 static wchar_t *retbuf;
1089 static size_t bsiz;
1090 wchar_t *p, *ret;
1092 if (alloc) {
1093 ret = p = xmalloc((strlen(from) + 1) * sizeof (wchar_t));
1094 } else {
1095 while (bsiz < (strlen(from) + 1)) {
1096 if ((p = reallocarray(retbuf, bsiz + 256,
1097 sizeof (wchar_t))) == NULL) {
1098 error(gettext("out of storage"));
1100 bsiz += 256;
1101 retbuf = p;
1103 ret = p = retbuf;
1106 if (wide) {
1107 while (*from) {
1108 int len;
1109 wchar_t wc;
1111 if ((len = mbtowc(&wc, from, mb_cur_max)) <= 0) {
1112 wc = *from | INVALID_CHAR;
1113 len = 1;
1115 *p++ = wc;
1116 from += len;
1118 } else {
1119 while (*from)
1120 *p++ = (unsigned char) *from++;
1122 *p = 0;
1124 return (ret);
1127 static wint_t
1128 myfgetwc(FILE *fp, int idx)
1130 int i, c, len, nb;
1131 wchar_t wc;
1132 unsigned char *buf;
1134 if (fp == NULL)
1135 fp = ifile[idx];
1136 else
1137 idx = 10; /* extra slot */
1138 buf = ibuffer[idx].buffer;
1139 nb = ibuffer[idx].nbytes;
1140 len = 0;
1141 for (i = 1; i <= mb_cur_max; i++) {
1142 if (nb < i) {
1143 c = getc(fp);
1144 if (c == EOF) {
1145 if (nb == 0)
1146 return (WEOF);
1147 else
1148 break;
1150 buf[nb++] = (unsigned char)c;
1152 if ((len = mbtowc(&wc, (char *)buf, i)) >= 0)
1153 break;
1155 if (len <= 0) {
1156 wc = buf[0] | INVALID_CHAR;
1157 len = 1;
1159 nb -= len;
1160 if (nb > 0) {
1161 for (i = 0; i < nb; i++)
1162 buf[i] = buf[i + len];
1164 ibuffer[idx].nbytes = nb;
1165 return (wc);
1168 static wint_t
1169 myfputwc(wchar_t wc, FILE *fp)
1171 if (wc & INVALID_CHAR) {
1172 wc &= ~INVALID_CHAR;
1173 return (fputc((int)wc, fp));
1175 return (fputwc(wc, fp));
1178 static int
1179 myfeof(int idx)
1181 return (ibuffer[idx].nbytes == 0 && feof(ifile[idx]));