9de972ade07440de06330656ed488d65de24580f
[mes.git] / lib / stdio / vfprintf.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * GNU Mes --- Maxwell Equations of Software
3  * Copyright © 2017,2018,2019 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 <mes/lib.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 int
27 vfprintf (FILE * f, char const *format, va_list ap)
28 {
29   int fd = (long) f;
30   char const *p = format;
31   int count = 0;
32   while (*p)
33     if (*p != '%')
34       {
35         count++;
36         fputc (*p++, f);
37       }
38     else
39       {
40         p++;
41         char c = *p;
42         int left_p = 0;
43         int precision = -1;
44         int width = -1;
45         if (c == '-')
46           {
47             left_p = 1;
48             c = *++p;
49           }
50         char pad = ' ';
51         if (c == '0')
52           {
53             pad = c;
54             c = *p++;
55           }
56         if (c >= '0' && c <= '9')
57           {
58             width = abtol (&p, 10);
59             c = *p;
60           }
61         else if (c == '*')
62           {
63             width = va_arg (ap, int);
64             c = *++p;
65           }
66         if (c == '.')
67           {
68             c = *++p;
69             if (c >= '0' && c <= '9')
70               {
71                 precision = abtol (&p, 10);
72                 c = *p;
73               }
74             else if (c == '*')
75               {
76                 precision = va_arg (ap, int);
77                 c = *++p;
78               }
79           }
80         if (c == 'l')
81           c = *++p;
82         if (c == 'l')
83           {
84             eputs ("vfprintf: skipping second: l\n");
85             c = *++p;
86           }
87         switch (c)
88           {
89           case '%':
90             {
91               fputc (*p, f);
92               count++;
93               break;
94             }
95           case 'c':
96             {
97               char _c;
98               _c = va_arg (ap, long);
99               fputc (_c, f);
100               break;
101             }
102           case 'd':
103           case 'i':
104           case 'o':
105           case 'u':
106           case 'x':
107           case 'X':
108             {
109               long d = va_arg (ap, long);
110               int base = c == 'o' ? 8 : c == 'x' || c == 'X' ? 16 : 10;
111               char *s = ntoab (d, base, c != 'u' && c != 'x' && c != 'X');
112               if (c == 'X')
113                 strupr (s);
114               int length = strlen (s);
115               if (precision == -1)
116                 precision = length;
117               if (!left_p)
118                 {
119                   while (width-- > precision)
120                     {
121                       fputc (pad, f);
122                       count++;
123                     }
124                   while (precision > length)
125                     {
126                       fputc ('0', f);
127                       precision--;
128                       width--;
129                       count++;
130                     }
131                 }
132               while (*s)
133                 {
134                   if (precision-- <= 0)
135                     break;
136                   width--;
137                   fputc (*s++, f);
138                   count++;
139                 }
140               while (width > 0)
141                 {
142                   width--;
143                   fputc (pad, f);
144                   count++;
145                 }
146               break;
147             }
148           case 's':
149             {
150               char *s = va_arg (ap, char *);
151               int length = strlen (s);
152               if (precision == -1)
153                 precision = length;
154               if (!left_p)
155                 {
156                   while (width-- > precision)
157                     {
158                       fputc (pad, f);
159                       count++;
160                     }
161                   while (precision > length)
162                     {
163                       fputc (' ', f);
164                       precision--;
165                       width--;
166                       count++;
167                     }
168                 }
169               while (*s)
170                 {
171                   if (precision-- <= 0)
172                     break;
173                   width--;
174                   fputc (*s++, f);
175                   count++;
176                 }
177               while (width > 0)
178                 {
179                   width--;
180                   fputc (pad, f);
181                   count++;
182                 }
183               break;
184             }
185           case 'f':
186           case 'e':
187           case 'E':
188           case 'g':
189           case 'G':
190             {
191               double d = va_arg (ap, double);
192               char *s = dtoab (d, 10, 1);
193               if (c == 'E' || c == 'G')
194                 strupr (s);
195               int length = strlen (s);
196               if (precision == -1)
197                 precision = length;
198               if (!left_p)
199                 {
200                   while (width-- > precision)
201                     {
202                       fputc (pad, f);
203                       count++;
204                     }
205                   while (precision > length)
206                     {
207                       fputc ('0', f);
208                       precision--;
209                       width--;
210                       count++;
211                     }
212                 }
213               while (*s)
214                 {
215                   if (precision-- <= 0)
216                     break;
217                   width--;
218                   fputc (*s++, f);
219                   count++;
220                 }
221               while (width > 0)
222                 {
223                   width--;
224                   fputc (pad, f);
225                   count++;
226                 }
227               break;
228             }
229           case 'n':
230             {
231               int *n = va_arg (ap, int *);
232               *n = count;
233               break;
234             }
235           default:
236             {
237               eputs ("vfprintf: not supported: %:");
238               eputc (c);
239               eputs ("\n");
240               p++;
241             }
242           }
243         p++;
244       }
245   va_end (ap);
246   return 0;
247 }