mescc: Mes C Library: Explode libc+tcc.c.
[mes.git] / lib / stdio / vfprintf.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * GNU Mes --- Maxwell Equations of Software
3  * Copyright © 2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
4  *
5  * This file is part of GNU Mes.
6  *
7  * GNU Mes is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or (at
10  * your option) any later version.
11  *
12  * GNU Mes is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 int
26 vfprintf (FILE* f, char const* format, va_list ap)
27 {
28   int fd = (int)f;
29   char const *p = format;
30   int count = 0;
31   while (*p)
32     if (*p != '%')
33       {
34         count++;
35         fputc (*p++, fd);
36       }
37     else
38       {
39         p++;
40         char c = *p;
41         int left_p = 0;
42         int precision = -1;
43         int width = -1;
44         if (c == '-')
45           {
46             left_p = 1;
47             c = *++p;
48           }
49         char pad = ' ';
50         if (c == '0')
51           {
52             pad = c;
53             c = *p++;
54           }
55         if (c >= '0' && c <= '9')
56           {
57             width = abtol (&p, 10);
58             c = *p;
59           }
60         else if (c == '*')
61           {
62             width = va_arg (ap, int);
63             c = *++p;
64           }
65         if (c == '.')
66           {
67             c = *++p;
68             if (c >= '0' && c <= '9')
69               {
70                 precision = abtol (&p, 10);
71                 c = *p;
72               }
73             else if (c == '*')
74               {
75                 precision = va_arg (ap, int);
76                 c = *++p;
77               }
78           }
79         if (c == 'l')
80           c = *++p;
81         if (c == 'l')
82           {
83             eputs ("vfprintf: skipping second: l\n");
84             c = *++p;
85           }
86         switch (c)
87           {
88           case '%': {fputc (*p, fd); count++; break;}
89           case 'c': {char c; c = va_arg (ap, int); fputc (c, fd); break;}
90           case 'd':
91           case 'i':
92           case 'o':
93           case 'u':
94           case 'x':
95           case 'X':
96             {
97               int d = va_arg (ap, int);
98               int base = c == 'o' ? 8
99                 : c == 'x' || c == 'X' ? 16
100                 : 10;
101               char const *s = ntoab (d, base, c != 'u' && c != 'x' && c != 'X');
102               if (c == 'X')
103                 strupr (s);
104               int length = strlen (s);
105               if (precision == -1)
106                 precision = length;
107               if (!left_p)
108                 {
109                   while (width-- > precision)
110                     {
111                       fputc (pad, f);
112                       count++;
113                     }
114                   while (precision > length)
115                     {
116                       fputc ('0', f);
117                       precision--;
118                       width--;
119                       count++;
120                     }
121                 }
122               while (*s)
123                 {
124                   if (precision-- <= 0)
125                     break;
126                   width--;
127                   fputc (*s++, f);
128                   count++;
129                 }
130               while (width > 0)
131                 {
132                   width--;
133                   fputc (pad, f);
134                   count++;
135                 }
136               break;
137             }
138           case 's':
139             {
140               char *s = va_arg (ap, char *);
141               int length = strlen (s);
142               if (precision == -1)
143                 precision = length;
144               if (!left_p)
145                 {
146                   while (width-- > precision)
147                     {
148                       fputc (pad, f);
149                       count++;
150                     }
151                   while (precision > length)
152                     {
153                       fputc (' ', f);
154                       precision--;
155                       width--;
156                       count++;
157                     }
158                 }
159               while (*s)
160                 {
161                   if (precision-- <= 0)
162                     break;
163                   width--;
164                   fputc (*s++, f);
165                   count++;
166                 }
167               while (width > 0)
168                 {
169                   width--;
170                   fputc (pad, f);
171                   count++;
172                 }
173               break;
174             }
175           case 'n':
176             {
177               int *n = va_arg (ap, int *);
178               *n = count;
179               break;
180             }
181           default:
182             {
183               eputs ("vfprintf: not supported: %:");
184               eputc (c);
185               eputs ("\n");
186               p++;
187             }
188           }
189         p++;
190       }
191   va_end (ap);
192   return 0;
193 }