stdio: conversion specifiers should immediately follow length modifiers
[neatlibc.git] / stdio.c
blob995719e2cc5a08b3bfa2a29ac2ee0bf96401a263
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
9 #define BUFSZ 1024
11 static char _ibuf[BUFSZ], _obuf[BUFSZ], _ebuf[BUFSZ];
12 static FILE _stdin = {0, EOF, _ibuf, NULL, BUFSZ, 0};
13 static FILE _stdout = {1, EOF, NULL, _obuf, 0, BUFSZ};
14 static FILE _stderr = {2, EOF, NULL, _ebuf, 0, 1};
15 FILE *stdin = &_stdin;
16 FILE *stdout = &_stdout;
17 FILE *stderr = &_stderr;
19 FILE *fopen(char *path, char *mode)
21 FILE *fp;
22 int flags;
24 if (strchr(mode, '+'))
25 flags = O_RDWR;
26 else
27 flags = *mode == 'r' ? O_RDONLY : O_WRONLY;
28 if (*mode != 'r')
29 flags |= O_CREAT;
30 if (*mode == 'w')
31 flags |= O_TRUNC;
32 if (*mode == 'a')
33 flags |= O_APPEND;
35 fp = malloc(sizeof(*fp));
36 memset(fp, 0, sizeof(*fp));
37 fp->fd = open(path, flags, 0600);
38 if (fp->fd < 0) {
39 free(fp);
40 return NULL;
42 fp->back = EOF;
43 fp->ibuf = malloc(BUFSZ);
44 fp->obuf = malloc(BUFSZ);
45 fp->isize = BUFSZ;
46 fp->osize = BUFSZ;
47 fp->iown = 1;
48 fp->oown = 1;
49 return fp;
52 int fclose(FILE *fp)
54 int ret = close(fp->fd);
55 if (fp->iown)
56 free(fp->ibuf);
57 if (fp->oown)
58 free(fp->obuf);
59 free(fp);
60 return ret;
63 int fflush(FILE *fp)
65 if (fp->fd < 0)
66 return 0;
67 if (write(fp->fd, fp->obuf, fp->olen) != fp->olen)
68 return EOF;
69 fp->olen = 0;
70 return 0;
73 static int oc(FILE *fp, int c)
75 if (fp->olen < fp->osize) {
76 fp->obuf[fp->olen++] = c;
77 fp->ostat++;
79 if (c == '\n' || fp->olen == fp->osize)
80 fflush(fp);
81 return c;
84 static void ostr(FILE *fp, char *s, int wid)
86 int fill = wid - strlen(s);
87 while (fill-- > 0)
88 oc(fp, ' ');
89 while (*s)
90 oc(fp, *s++);
93 static int digits(unsigned long n, int base)
95 int i;
96 for (i = 0; n; i++)
97 n /= base;
98 return i ? i : 1;
101 static char *digs = "0123456789abcdef";
103 static void oint(FILE *fp, unsigned long n, int base, int sign,
104 int wid, int fill, int psign)
106 char buf[64];
107 char *s = buf;
108 int neg = 0;
109 int d;
110 int i;
111 if (sign && (signed long) n < 0) {
112 neg = 1;
113 n = -n;
115 d = digits(n, base);
116 for (i = 0; i < d; i++) {
117 s[d - i - 1] = digs[n % base];
118 n /= base;
120 s[d] = '\0';
121 for (i = d + neg; i < wid; i++)
122 oc(fp, fill);
123 if (neg || psign)
124 oc(fp, neg ? '-' : '+');
125 ostr(fp, buf, 0);
128 int vfprintf(FILE *fp, char *fmt, va_list ap)
130 char *s = fmt;
131 int beg = fp->ostat;
132 while (*s) {
133 int c = *s++;
134 int fill = ' ';
135 int wid = 0;
136 int psign = 0; /* add sign as in %+d */
137 if (c != '%') {
138 oc(fp, c);
139 continue;
141 if (*s == '0') {
142 fill = '0';
143 s++;
145 while (isdigit(*s)) {
146 wid *= 10;
147 wid += *s++ - '0';
149 if (*s == '+') {
150 psign = 1;
151 s++;
153 if (*s == 'l' || *s == 'h')
154 s++;
155 switch ((c = *s++)) {
156 case 'd':
157 oint(fp, va_arg(ap, long), 10, 1, wid, fill, psign);
158 break;
159 case 'u':
160 oint(fp, va_arg(ap, long), 10, 0, wid, fill, 0);
161 break;
162 case 'x':
163 case 'p':
164 oint(fp, va_arg(ap, long), 16, 0, wid, fill, 0);
165 break;
166 case 'c':
167 oc(fp, va_arg(ap, int));
168 break;
169 case 's':
170 ostr(fp, va_arg(ap, char *), wid);
171 break;
172 case '\0':
173 s--;
174 break;
175 default:
176 oc(fp, c);
179 return fp->ostat - beg;
182 void perror(char *s)
184 int idx = errno;
185 if (idx >= sys_nerr)
186 idx = 0;
187 fprintf(stderr, "%s: %s\n", s, sys_errlist[idx]);
190 int vsnprintf(char *dst, int sz, char *fmt, va_list ap)
192 FILE f = {-1, EOF};
193 int ret;
194 f.obuf = dst;
195 f.osize = sz - 1;
196 ret = vfprintf(&f, fmt, ap);
197 dst[f.olen] = '\0';
198 return ret;
201 int vsprintf(char *dst, char *fmt, va_list ap)
203 return vsnprintf(dst, 1 << 20, fmt, ap);
206 int printf(char *fmt, ...)
208 va_list ap;
209 int ret;
210 va_start(ap, fmt);
211 ret = vfprintf(stdout, fmt, ap);
212 va_end(ap);
213 return ret;
216 int fprintf(FILE *fp, char *fmt, ...)
218 va_list ap;
219 int ret;
220 va_start(ap, fmt);
221 ret = vfprintf(fp, fmt, ap);
222 va_end(ap);
223 return ret;
226 int sprintf(char *dst, char *fmt, ...)
228 va_list ap;
229 int ret;
230 va_start(ap, fmt);
231 ret = vsprintf(dst, fmt, ap);
232 va_end(ap);
233 return ret;
236 int snprintf(char *dst, int sz, char *fmt, ...)
238 va_list ap;
239 int ret;
240 va_start(ap, fmt);
241 ret = vsnprintf(dst, sz, fmt, ap);
242 va_end(ap);
243 return ret;