3 * (C) Copyright Dec 19 1998, Edmond J. Breen.
5 * This code may be copied for personal, non-profit use only.
9 /* This file is broken into 2 parts
10 * the first part defines the interface routines
11 * and the 2nd part adds the interface routine
12 * to EiC's look up tables.
21 #define _POSIX_SOURCE 1
24 #ifndef __EXTENSIONS__
25 #define __EXTENSIONS__
37 extern FILE *popen(const char *, const char *);
38 extern int pclose(FILE *);
53 #include "stdliblocal.h"
61 /* The following code provides for an open FILE cleanup
62 mechanism. EiC will call _ffexit, cleaning up all open
63 FILEs which were opened in the side effects being discarded.
65 static size_t NextFopenEntry = 4;
67 static size_t book1[FOPEN_MAX] = {1,2,3};
68 static FILE * book2[FOPEN_MAX];
70 size_t fopen_NextEntryNum(void) {
71 return NextFopenEntry;
74 /* We assume that eic_fopen() is always closed by eic_fclose()
75 and eic_popen() is aways closed by eic_pclose() so that book[i]
76 being non-zero implies that the associated FILE is still open.
77 This ignores the possibility that a file opened in interpreted
78 code can be closed in compiled code, but such a situation is
79 ill advised in any event.
81 void _ffexit(size_t Entry) {
83 for(i = 0; i < FOPEN_MAX; i += 1) {
84 if(book1[i] >= Entry) {
93 /* INTERFACE FUNCTIONS */
95 int charin_(char **buf)
105 int charback_(int ch, char **buf)
111 int charout_(int c, char **buf)
122 /*int _eicUprintf(int (*output)(), void *arg, char *fmt, arg_list ap)*/
125 int _eicUprintf(int (*output)(), char**arg, char *fmt, arg_list ap)
128 /* copy of _UPRINTF that works with EiC's run time stack.
129 * Orginally developed from James Hendrix's Small C tools.
131 * (c) Edmond J.Breen (March, 1995).
132 * ALL RIGHTS RESERVED.
134 * Purpose: To perform formatted printing to a function.
135 * It performs a superset of printf type
138 * _UPRINTF RECOGNISES:
141 * plus ! and | (see below).
143 * CONVERSION CHARACTERS:
144 * d, i, o, x, X, u, c, s,
145 * f, e, E, g, G, p, n, %
146 * plus b (see below).
151 * The WIDTH and or the PRECISION can be set indirectly
152 * via * as specified by K&R.
154 * _UPRINTF EXTRA FEATURES.
156 * FLAG WHAT IT SPECIFIES
157 * | Centre justification.
158 * ! Used with floating point numbers.
159 * It specifies, if possible, that the
160 * number will be centred with respect
161 * to the decimal point.
162 * If used with non floating point
163 * numbers or the floating point number
164 * does not contain a decimal point,
165 * the ! flag is equivalent to |.
166 * NEW CONVERSION CHARACTER:
167 * CHARACTER WHAT IT SPECIFIES
168 * b int, unsigned binary notation.
173 static char str[128];
174 char *sptr, lseen,Lseen;
176 int left, right, centre, maxchr,
177 pad, len, width, sign, dprec,
178 mod, prec,dot,gotfloat;
187 } else if(*++fmt =='%') {
188 (*output)(*fmt++,arg);
193 centre = len = right = left = 0;
194 gotfloat = dot = sign = mod = 0;
195 Lseen = lseen = dprec = 0;
196 while(*fmt) { /* collect in any order */
197 if(*fmt == '-') left = 1;
198 else if(*fmt == '0') pad = '0';
199 else if(*fmt == '+') sign = 1;
200 else if(*fmt == '#') mod = 1;
201 else if(*fmt == '|') centre = 1;
202 else if(*fmt == '!') centre = 1, dot = 1;
209 while(isdigit(*fmt)) ++fmt;
210 } else if(*fmt == '*') {
211 width = nextarg(ap,int);
217 maxchr = nextarg(ap,int);
221 while(isdigit(*fmt)) ++fmt;
226 switch(*fmt) { /* check for length modifier*/
227 case 'h': fmt++;break;
228 case 'l': lseen = 1; fmt++;break;
229 case 'L': Lseen = 1; fmt++;break;
233 case 'c': sptr[0] = (char)nextarg(ap,int);
237 if(lseen) ultoa(nextarg(ap,long),sptr,2);
238 else utoa(nextarg(ap,int),sptr,2);
241 case 'd': if(lseen) ltoa(nextarg(ap,long),sptr,10);
242 else itoa(nextarg(ap,int),sptr,10);
245 case 'u': if(lseen) ultoa(nextarg(ap,unsigned long),sptr,10);
246 else utoa(nextarg(ap,unsigned),sptr,10);
249 case 'o': if(mod) *sptr = '0';
250 if(lseen)ltoa(nextarg(ap,long),&sptr[mod],8);
251 else itoa(nextarg(ap,int),&sptr[mod],8);
254 case 's': sptr = nextarg(ap,ptr_t).p; break;
257 *sptr = '0', sptr[1] = *(fmt-1);
260 if(lseen)ultoa(nextarg(ap,long),&sptr[mod],16);
261 else utoa(nextarg(ap,int),&sptr[mod],16);
262 if(*(fmt-1) == 'X') {
264 *sptr = toupper(*sptr);
272 case 'e': case 'E': case 'g': case 'G':
275 char type = *(fmt-1),c;
279 if(maxchr < 0) prec = 6;
280 else prec = maxchr,maxchr = -1;
283 d = nextarg(ap,double);
285 d = nextarg(ap,double);
287 if(type == 'g' || type == 'G') {
290 ex = log10(d < 0? -d:d);
293 if(ex < -4 || ex >= prec)
304 sptr = fftoa(d,str, prec, c,trunc);
307 case 'n': *(int*)nextarg(ap,ptr_t).p = v; continue;
309 ultoa((long)nextarg(ap,ptr_t).p,sptr,16);
311 default: (*output)(*(fmt-1),arg);
313 (*output)(*fmt++,arg);
320 if(!len && sptr) len = strlen(sptr);
321 if(sign) len += (*sptr == '-' ? 0: 1);
323 if(dprec && maxchr >=0) {
331 if(maxchr > -1 && maxchr<len)
341 left = (right = width >> 1) + (width%2);
342 if(dot && gotfloat) {
344 while(sptr[d] && sptr[d] != '.')
348 if(sign && sptr[0] != '-')
350 if(c-d > 0) right = c-d;
352 if(width - right > 0)
353 left = width - right;
364 if(sign && !left && pad == '0') {
371 while(right--) {(*output)(pad,arg); ++v;}
372 if(sign && *sptr != '-') {(*output)('+',arg);len--;++v;}
373 while(len--) {(*output)(*sptr++,arg);++v;}
374 while(left--) {(*output)(pad,arg);++v;}
383 /*int _eicUscanf(int (*input)(), int (*uget)(),*/
384 /* void *arg, const char *fmt, arg_list ap)*/
387 int _eicUscanf(int (*input)(), int (*uget)(),
388 char **arg, const char *fmt, arg_list ap)
393 * (C) May 10 1995 Edmond J.Breen.
394 * ALL RIGHTS RESERVED.
396 * Purpose: To perform formatted reading from a function.
397 * _Uscanf performs a superset of scanf type
400 * _USCANF RECOGNISES:
402 * %[*] [width] [h|l|L] [b|d|i|o|x|X|u|c|s|f|e|E|g|G|p|n|%]
403 * %[*] [width] [scan-set]
405 * CONVERSION CHARACTERS:
406 * d, i, o, x, X, u, c, s
407 * f, e, E, g, G, p, n, %
408 * plus b (see below).
413 * * optional assignment-suppression character
414 * WIDTH optional integer width of field specifier
417 * [...] matches the longest non-emtpy string
418 * of input from the set between the brackects.
419 * [^...] matches the longest non-emtpy string
420 * of input NOT from the set between the brackects.
422 * includes ] as part of the scan-set.
424 * NEW CONVERSION CHARACTER:
425 * CHARACTER WHAT IT SPECIFIES
426 * b int, unsigned binary notation.
428 * STANDARD C AUXILIARY FUNCTIONS REQUIRED
429 * strtol, strtod, strtoul
432 * (1) long double handled as double
433 * (2) error checking could be improved
436 static char field[256], *p;
440 int wast, width,cwidth, ch, base,cnt;
447 while(*fmt != '\0') {
448 if(isspace(*fmt)) { /* match white space */
449 while(*fmt && isspace(*fmt)) ++fmt;
451 while(isspace((ch=(*input)(arg))))
457 if(*fmt != '%') { /* match literal text */
458 while(*fmt && !isspace(*fmt) && *fmt != '%')
459 if((ch=(*input)(arg)) == *fmt)
470 } else if(*fmt == '%') {
476 vptr = nextarg(ap,ptr_t).p;
479 for(width = 0;isdigit(*fmt);fmt++)
480 width = *fmt - '0' + width * 10;
482 width = INT_MAX, cwidth = 1;
486 if(*fmt != 'c' && *fmt != '[' && *fmt != 'n') {
487 /* strip leading white space */
488 while(isspace(ch = (*input)(arg)))
501 case 'h': type = 'h'; ++fmt; break;
502 case 'l': type = 'l'; ++fmt; break;
503 case 'L': type = 'L'; ++fmt; break;
508 case 'c': carg = vptr;
510 *carg = (*input)(arg);
519 if((*carg = (*input)(arg)) == EOF)
534 if(*fmt == '^') {++fmt; type = 0;}
540 while(*p && *p != ']') ++p;
542 if(cwidth == 0) return EOF;
544 while((ch = (*input)(arg)) != EOF)
546 if(memchr(fmt,ch,cwidth)) {
555 if(!memchr(fmt,ch,cwidth)) {
566 case 'e': case 'f': case 'g':
570 if(ch == '-' || ch == '+') {
575 while(width-- && isdigit(ch=(*input)(arg))) {
578 if(ch == '.' && width-- > 0) {
581 while(isdigit(ch=(*input)(arg)) && width--) {
586 if((ch == 'e' || ch == 'E') && width--) {
589 if(ch != '+' && ch != '-' && !isdigit(ch) &&
590 ch != EOF && !isspace(ch)) {
597 if((ch == '+' || ch == '-') && width--) {
602 while(isdigit(ch) && width--) {
612 double d = strtod(field,NULL);
613 if(!type || type == 'h')
614 *(float*)vptr = (float)d;
615 else if(type == 'l' || type == 'L')
630 case 'b': base = 2; break;
635 if(ch == '0') base = 8;
640 case 'o': base = 8; break;
643 case 'p': base = 16; break;
648 while(width-- && !isspace(ch=(*input)(arg)) && ch != EOF) {
661 if(*fmt == 'd' || *fmt == 'i') { /* signed conversion */
662 long lval = strtol(field,&endptr,base);
665 *(short *)vptr =(short) lval;
667 *(long *)vptr = lval;
669 *(int *)vptr = (int) lval;
672 unsigned long ulval = strtoul(field,&endptr,base);
675 *(unsigned short *)vptr =(unsigned short) ulval;
677 *(unsigned long *)vptr = ulval;
679 *(unsigned *)vptr = (unsigned)ulval;
681 if(endptr == field) /* failed */
701 arg_list ap = getargs();
704 v.p.sp = v.p.p = _popen(arg(0,ap,ptr_t).p,arg(1,ap,ptr_t).p);
706 v.p.sp = v.p.p = popen(arg(0,ap,ptr_t).p,arg(1,ap,ptr_t).p);
709 if((FILE *)(v.p.p) != NULL) {
711 for(i=1;i<FOPEN_MAX;i++)
714 book1[i] = NextFopenEntry++;
715 book2[i] = (FILE *)(v.p.p);
717 setEp( v.p, sizeof(FILE) );
727 arg_list ap = getargs();
729 ptr = arg(0,ap,ptr_t).p;
732 v.ival = _pclose(ptr);
734 v.ival = pclose(ptr);
737 for(i=0;i<FOPEN_MAX;i++)
750 val_t _get_stdin(void)
754 * This function exists so that EiC can get the address stdin.
756 v.p.sp = v.p.p = stdin;
757 setEp( v.p, sizeof(*stdin) );
760 val_t _get_stdout(void)
764 * This function exists so that EiC can get the address stdout.
766 v.p.sp = v.p.p = stdout;
767 setEp( v.p, sizeof(*stdout) );
770 val_t _get_stderr(void)
774 * This function exists so that EiC can get the address stderr.
776 v.p.sp = v.p.p = stderr;
777 setEp( v.p, sizeof(*stderr) );
783 val_t eic_ftell(void)
786 v.lval = ftell(arg(0,getargs(),ptr_t).p);
790 val_t eic_fseek(void)
793 v.ival = fseek(arg(0,getargs(),ptr_t).p,
794 arg(1,getargs(),long),
795 arg(2,getargs(),int));
801 val_t eic_printf(void)
804 arg_list ap = getargs();
807 fmt = nextarg(ap,ptr_t).p;
809 v.ival = _eicUprintf(outbyte,stdout,fmt,ap);
811 v.ival = _eicUprintf(fputc,stdout,fmt,ap);
816 val_t eic_fprintf(void)
819 arg_list ap = getargs();
823 fp = nextarg(ap,ptr_t).p;
824 fmt = nextarg(ap,ptr_t).p;
825 v.ival = _eicUprintf(fputc,fp,fmt,ap);
829 val_t eic_vfprintf(void)
832 arg_list ap = getargs();
837 fp = nextarg(ap,ptr_t).p;
838 fmt = nextarg(ap,ptr_t).p;
839 ags = nextarg(ap,arg_list);
840 v.ival = _eicUprintf(fputc,fp,fmt,ags);
844 val_t eic_sprintf(void)
847 arg_list ap = getargs();
849 str = nextarg(ap,ptr_t).p;
850 fmt = nextarg(ap,ptr_t).p;
851 v.ival = _eicUprintf(charout_,&str,fmt,ap);
856 val_t eic_vsprintf(void)
859 arg_list ap = getargs();
864 str = nextarg(ap,ptr_t).p;
865 fmt = nextarg(ap,ptr_t).p;
866 ags = nextarg(ap,arg_list);
867 v.ival = _eicUprintf(charout_,&str,fmt,ags);
872 val_t eic_freopen(void)
875 arg_list ap = getargs();
876 v.p.sp = v.p.p = freopen(arg(0,ap,ptr_t).p,
880 setEp( v.p, sizeof(FILE) );
884 val_t eic_fopen(void)
887 arg_list ap = getargs();
888 v.p.sp = v.p.p = fopen(arg(0,ap,ptr_t).p,
890 if((FILE *)(v.p.p) != NULL) {
892 for(i=1;i<FOPEN_MAX;i++)
895 book1[i] = NextFopenEntry++;
896 book2[i] = (FILE *)(v.p.p);
898 setEp( v.p, sizeof(FILE) );
902 val_t eic_ungetc(void)
905 arg_list ap = getargs();
906 v.ival = ungetc(arg(0,ap,int),
911 val_t eic_fgetc(void)
914 v.ival = fgetc(nextarg(getargs(),ptr_t).p);
917 val_t eic_fclose(void)
923 ptr = nextarg(getargs(),ptr_t).p;
925 for(i=0;i<FOPEN_MAX;i++)
933 v.ival = fclose(ptr);
936 val_t eic_fflush(void)
939 v.ival = fflush(nextarg(getargs(),ptr_t).p);
943 val_t eic_fputc(void)
946 arg_list ap = getargs();
947 v.ival = fputc(arg(0,ap,int),
955 arg_list ap = getargs();
956 v.ival = puts(arg(0,ap,ptr_t).p);
960 val_t eic_fputs(void)
963 arg_list ap = getargs();
964 v.ival = fputs(arg(0,ap,ptr_t).p,
969 val_t eic_fgets(void)
973 arg_list ap = getargs();
979 v.p.p = fgets(v.p.p,n, arg(2,ap,ptr_t).p);
989 n = (char*)v.p.ep - (char*)v.p.sp;
990 v.p.p = fgets(v.p.p,n,stdin);
994 val_t eic_fread(void)
997 arg_list ap = getargs();
998 v.szval = fread(arg(0,ap,ptr_t).p,
1005 val_t eic_fwrite(void)
1010 v.szval = fwrite(arg(0,ap,ptr_t).p,
1017 val_t eic_fscanf(void)
1020 arg_list ap = getargs();
1021 v.ival = _eicUscanf(fgetc,ungetc,
1023 arg(1,ap,ptr_t).p,ap-2);
1027 val_t eic_feof(void)
1031 v.ival = feof((FILE *)(v.p.p));
1035 val_t eic_ferror(void)
1039 v.ival = ferror((FILE *)(v.p.p));
1043 val_t eic_rewind(void)
1047 rewind((FILE *)(v.p.p));
1051 val_t eic_fsetpos(void)
1054 arg_list ap = getargs();
1055 v.ival = fsetpos(arg(0,ap,ptr_t).p,
1060 val_t eic_fgetpos(void)
1063 arg_list ap = getargs();
1064 v.ival = fgetpos(arg(0,ap,ptr_t).p,
1071 val_t eic_scanf(void)
1074 arg_list ap = getargs();
1075 v.ival = _eicUscanf(fgetc,ungetc,
1077 arg(0,ap,ptr_t).p,ap-1);
1081 val_t eic_sscanf(void)
1085 arg_list ap = getargs();
1086 str = arg(0,ap,ptr_t).p;
1087 v.ival = _eicUscanf(charin_,charback_,
1089 arg(1,ap,ptr_t).p,ap-2);
1093 val_t eic_setvbuf(void)
1096 arg_list ap = getargs();
1097 v.ival = setvbuf(arg(0,ap,ptr_t).p,
1105 val_t eic_tmpnam(void)
1108 v.p.sp = v.p.p = tmpnam(arg(0,getargs(),ptr_t).p);
1109 setEp( v.p, strlen(v.p.p) + 1 );
1112 val_t eic_tmpfile(void)
1115 v.p.sp = v.p.p = tmpfile();
1116 setEp( v.p, strlen(v.p.p) + 1 );
1120 val_t eic_rename(void)
1124 v.ival = rename(arg(0,getargs(),ptr_t).p,
1125 arg(1,getargs(),ptr_t).p);
1127 v.ival = link(arg(0,getargs(),ptr_t).p,
1128 arg(1,getargs(),ptr_t).p);
1130 v.ival = unlink(arg(0,getargs(),ptr_t).p);
1135 val_t eic_clearerr(void)
1138 clearerr((FILE *)(arg(0,getargs(),ptr_t).p));
1142 val_t eic_perror(void)
1145 perror(arg(0,getargs(),ptr_t).p);
1150 /**********************************************************************************/
1152 void module_stdio(void)
1159 /* stdio.h stuff that were macros */
1160 EiC_add_builtinfunc("puts", eic_puts);
1161 EiC_add_builtinfunc("feof", eic_feof);
1162 EiC_add_builtinfunc("ferror", eic_ferror);
1163 EiC_add_builtinfunc("rewind", eic_rewind);
1164 EiC_add_builtinfunc("fsetpos", eic_fsetpos);
1165 EiC_add_builtinfunc("fgetpos", eic_fgetpos);
1168 EiC_add_builtinfunc("_get_stdin",_get_stdin);
1169 EiC_add_builtinfunc("_get_stdout",_get_stdout);
1170 EiC_add_builtinfunc("_get_stderr",_get_stderr);
1171 EiC_add_builtinfunc("ftell", eic_ftell);
1172 EiC_add_builtinfunc("freopen",eic_freopen);
1173 EiC_add_builtinfunc("fopen",eic_fopen);
1174 EiC_add_builtinfunc("printf", eic_printf);
1175 EiC_add_builtinfunc("fprintf", eic_fprintf);
1176 EiC_add_builtinfunc("sprintf", eic_sprintf);
1177 EiC_add_builtinfunc("vfprintf", eic_vfprintf);
1178 EiC_add_builtinfunc("vsprintf", eic_vsprintf);
1179 EiC_add_builtinfunc("ungetc", eic_ungetc);
1180 EiC_add_builtinfunc("fgetc", eic_fgetc);
1181 EiC_add_builtinfunc("fputc", eic_fputc);
1182 EiC_add_builtinfunc("fputs", eic_fputs);
1183 EiC_add_builtinfunc("fgets", eic_fgets);
1184 EiC_add_builtinfunc("gets", eic_gets);
1185 EiC_add_builtinfunc("fread", eic_fread);
1186 EiC_add_builtinfunc("fwrite", eic_fwrite);
1187 EiC_add_builtinfunc("fflush", eic_fflush);
1188 EiC_add_builtinfunc("fclose", eic_fclose);
1189 EiC_add_builtinfunc("fscanf", eic_fscanf);
1190 EiC_add_builtinfunc("sscanf", eic_sscanf);
1191 EiC_add_builtinfunc("scanf", eic_scanf);
1192 EiC_add_builtinfunc("setvbuf", eic_setvbuf);
1193 EiC_add_builtinfunc("tmpnam", eic_tmpnam);
1194 EiC_add_builtinfunc("tmpfile", eic_tmpfile);
1195 EiC_add_builtinfunc("rename",eic_rename);
1196 EiC_add_builtinfunc("fseek", eic_fseek);
1197 EiC_add_builtinfunc("clearerr", eic_clearerr);
1198 EiC_add_builtinfunc("perror", eic_perror);
1202 EiC_add_builtinfunc("popen", eic_popen);
1203 EiC_add_builtinfunc("pclose", eic_pclose);