stdio: puts() and vprintf()
[neatlibc.git] / stdio.c
blob7c396f1b45a34e41ca74f17836b49d3fbce3def4
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
10 #define BUFSZ 1024
12 static char _ibuf[BUFSZ], _obuf[BUFSZ], _ebuf[BUFSZ];
13 static FILE _stdin = {0, EOF, _ibuf, NULL, BUFSZ, 0};
14 static FILE _stdout = {1, EOF, NULL, _obuf, 0, BUFSZ};
15 static FILE _stderr = {2, EOF, NULL, _ebuf, 0, 1};
16 FILE *stdin = &_stdin;
17 FILE *stdout = &_stdout;
18 FILE *stderr = &_stderr;
20 FILE *fopen(char *path, char *mode)
22 FILE *fp;
23 int flags;
25 if (strchr(mode, '+'))
26 flags = O_RDWR;
27 else
28 flags = *mode == 'r' ? O_RDONLY : O_WRONLY;
29 if (*mode != 'r')
30 flags |= O_CREAT;
31 if (*mode == 'w')
32 flags |= O_TRUNC;
33 if (*mode == 'a')
34 flags |= O_APPEND;
36 fp = malloc(sizeof(*fp));
37 memset(fp, 0, sizeof(*fp));
38 fp->fd = open(path, flags, 0600);
39 if (fp->fd < 0) {
40 free(fp);
41 return NULL;
43 fp->back = EOF;
44 fp->ibuf = malloc(BUFSZ);
45 fp->obuf = malloc(BUFSZ);
46 fp->isize = BUFSZ;
47 fp->osize = BUFSZ;
48 fp->iown = 1;
49 fp->oown = 1;
50 return fp;
53 int fclose(FILE *fp)
55 int ret = close(fp->fd);
56 if (fp->iown)
57 free(fp->ibuf);
58 if (fp->oown)
59 free(fp->obuf);
60 free(fp);
61 return ret;
64 int fflush(FILE *fp)
66 if (fp->fd < 0)
67 return 0;
68 if (write(fp->fd, fp->obuf, fp->olen) != fp->olen)
69 return EOF;
70 fp->olen = 0;
71 return 0;
74 static int oc(FILE *fp, int c)
76 if (fp->olen < fp->osize) {
77 fp->obuf[fp->olen++] = c;
78 fp->ostat++;
80 if (c == '\n' || fp->olen == fp->osize)
81 fflush(fp);
82 return c;
85 static void ostr(FILE *fp, char *s, int wid)
87 int fill = wid - strlen(s);
88 while (fill-- > 0)
89 oc(fp, ' ');
90 while (*s)
91 oc(fp, (unsigned char) *s++);
94 static int digits(unsigned long n, int base)
96 int i;
97 for (i = 0; n; i++)
98 n /= base;
99 return i ? i : 1;
102 static char *digs = "0123456789abcdef";
104 static void oint(FILE *fp, unsigned long n, int base, int sign,
105 int wid, int fill, int psign, int bytes)
107 char buf[64];
108 char *s = buf;
109 int neg = 0;
110 int d;
111 int i;
112 if (sign && (signed long) n < 0) {
113 neg = 1;
114 n = -n;
116 if (bytes == 1)
117 n &= 0x000000ff;
118 if (bytes == 2)
119 n &= 0x0000ffff;
120 if (bytes == 4)
121 n &= 0xffffffff;
122 d = digits(n, base);
123 for (i = 0; i < d; i++) {
124 s[d - i - 1] = digs[n % base];
125 n /= base;
127 s[d] = '\0';
128 for (i = d + neg; i < wid; i++)
129 oc(fp, fill);
130 if (neg || psign)
131 oc(fp, neg ? '-' : '+');
132 ostr(fp, buf, 0);
135 int vfprintf(FILE *fp, char *fmt, va_list ap)
137 char *s = fmt;
138 int beg = fp->ostat;
139 while (*s) {
140 int c = (unsigned char) *s++;
141 int fill = ' ';
142 int wid = 0;
143 int psign = 0; /* add sign as in %+d */
144 int bytes = sizeof(int);
145 if (c != '%') {
146 oc(fp, c);
147 continue;
149 if (*s == '0') {
150 fill = '0';
151 s++;
153 while (isdigit(*s)) {
154 wid *= 10;
155 wid += *s++ - '0';
157 if (*s == '+') {
158 psign = 1;
159 s++;
161 while (*s == 'l') {
162 bytes = sizeof(long);
163 s++;
165 while (*s == 'h') {
166 bytes = bytes < sizeof(int) ? sizeof(char) : sizeof(short);
167 s++;
169 switch ((c = *s++)) {
170 case 'd':
171 oint(fp, va_arg(ap, long), 10, 1, wid, fill, psign, bytes);
172 break;
173 case 'u':
174 oint(fp, va_arg(ap, long), 10, 0, wid, fill, 0, bytes);
175 break;
176 case 'x':
177 case 'p':
178 oint(fp, va_arg(ap, long), 16, 0, wid, fill, 0, bytes);
179 break;
180 case 'c':
181 oc(fp, va_arg(ap, int));
182 break;
183 case 's':
184 ostr(fp, va_arg(ap, char *), wid);
185 break;
186 case '\0':
187 s--;
188 break;
189 default:
190 oc(fp, c);
193 return fp->ostat - beg;
196 void perror(char *s)
198 int idx = errno;
199 if (idx >= sys_nerr)
200 idx = 0;
201 fprintf(stderr, "%s: %s\n", s, sys_errlist[idx]);
204 int vsnprintf(char *dst, int sz, char *fmt, va_list ap)
206 FILE f = {-1, EOF};
207 int ret;
208 f.obuf = dst;
209 f.osize = sz - 1;
210 ret = vfprintf(&f, fmt, ap);
211 dst[f.olen] = '\0';
212 return ret;
215 int vsprintf(char *dst, char *fmt, va_list ap)
217 return vsnprintf(dst, 1 << 20, fmt, ap);
220 int printf(char *fmt, ...)
222 va_list ap;
223 int ret;
224 va_start(ap, fmt);
225 ret = vfprintf(stdout, fmt, ap);
226 va_end(ap);
227 return ret;
230 int vprintf(char *fmt, va_list ap)
232 vfprintf(stdout, fmt, ap);
235 int fprintf(FILE *fp, char *fmt, ...)
237 va_list ap;
238 int ret;
239 va_start(ap, fmt);
240 ret = vfprintf(fp, fmt, ap);
241 va_end(ap);
242 return ret;
245 int sprintf(char *dst, char *fmt, ...)
247 va_list ap;
248 int ret;
249 va_start(ap, fmt);
250 ret = vsprintf(dst, fmt, ap);
251 va_end(ap);
252 return ret;
255 int snprintf(char *dst, int sz, char *fmt, ...)
257 va_list ap;
258 int ret;
259 va_start(ap, fmt);
260 ret = vsnprintf(dst, sz, fmt, ap);
261 va_end(ap);
262 return ret;
265 int fputs(char *s, FILE *fp)
267 while (*s)
268 oc(fp, (unsigned char) *s++);
269 return 0;
272 int puts(char *s)
274 int ret = fputs(s, stdout);
275 if (ret >= 0)
276 oc(stdout, '\n');
277 return ret;