]> wirehaze git hosting - ppos.git/blob - ppos/lib/libc.c

wirehaze git hosting

tasks implementation (ongoing)
[ppos.git] / ppos / lib / libc.c
1 // PingPongOS - PingPong Operating System
2 // Prof. Carlos A. Maziero, DINF UFPR
3 // Versão 2.0 -- Junho de 2025
4
5 // ATENÇÃO: ESTE ARQUIVO NÃO DEVE SER ALTERADO;
6 // ALTERAÇÕES SERÃO DESCARTADAS NA CORREÇÃO.
7
8 // Funções básicas da biblioteca C, que devem ser definidas aqui
9 // para nos liberar da GLibC.
10
11 #include "hardware/serial.h"
12 #include <stdbool.h>
13 #include "libc.h"
14
15 // macros do compilador para funções variádicas (usadas no printk)
16 #define va_list __builtin_va_list
17 #define va_start __builtin_va_start
18 #define va_end __builtin_va_end
19 #define va_arg __builtin_va_arg
20
21 // estado interno do gerador de números pseudo-aleatórios
22 // https://en.wikipedia.org/wiki/Linear_congruential_generator
23 static unsigned int rand_number = 0;
24
25 //----------------------------------------------------------------------
26
27 void randseed(unsigned long seed)
28 {
29 rand_number = seed;
30 }
31
32 //----------------------------------------------------------------------
33
34 unsigned long randnum(void)
35 {
36 // rand_number = (1103515245L * rand_number + 12345) % (1 << 30);
37 rand_number = (1664525L * rand_number + 1013904223L) % (1L << 31);
38 return (rand_number);
39 }
40
41 //----------------------------------------------------------------------
42
43 int abs(int num)
44 {
45 if (num < 0)
46 return (-num);
47 else
48 return (num);
49 }
50
51 //----------------------------------------------------------------------
52
53 int mem_copy(const char *orig, char *dest, int size)
54 {
55 if (!orig || !dest || size <= 0)
56 return (ERROR);
57
58 for (int i = 0; i < size; i++)
59 dest[i] = orig[i];
60
61 return (NOERROR);
62 }
63
64 //----------------------------------------------------------------------
65
66 void putch(char c)
67 {
68 hw_serial_put(c);
69 }
70
71 //----------------------------------------------------------------------
72
73 void putst(const char *s)
74 {
75 if (!s)
76 s = "NULL";
77
78 while (*s)
79 {
80 putch(*s);
81 s++;
82 }
83 }
84
85 //----------------------------------------------------------------------
86
87 // adaptado de from: https://operating-system-in-1000-lines.vercel.app/en/
88 void printk(const char *fmt, ...)
89 {
90 bool left_align;
91 //bool fill_zeros = false;
92 //bool signal_space = false;
93 short width;
94 va_list vargs;
95
96 va_start(vargs, fmt);
97
98 while (*fmt)
99 {
100 // find a % mark, process it
101 if (*fmt == '%')
102 {
103 // skip '%'
104 fmt++;
105
106 // space for signal (% )
107 /*if (*fmt == ' ')
108 {
109 signal_space = true;
110 fmt++;
111 }*/
112
113 // left alignment (%-)
114 left_align = false;
115 if (*fmt == '-')
116 {
117 left_align = true;
118 fmt++;
119 }
120
121 // fill with zeros (%0)
122 /*if (*fmt == '0')
123 {
124 fill_zeros = true;
125 fmt++;
126 }*/
127
128 // width modifier (%NN)
129 width = 0;
130 while (*fmt && *fmt >= '1' && *fmt <= '9')
131 {
132 width = 10 * width + (*fmt - '0');
133 fmt++;
134 }
135
136 switch (*fmt)
137 {
138
139 // "%%" or '%' at the end of the format string
140 case '%':
141 case '\0':
142 putch('%');
143 break;
144
145 // %c: char
146 case 'c':
147 {
148 int c = va_arg(vargs, int);
149 putch(c);
150 break;
151 }
152
153 // %s: string
154 case 's':
155 {
156 const char *s = va_arg(vargs, const char *);
157 char *aux;
158
159 // null string
160 if (!s)
161 s = "(null)";
162
163 // decrement width according to string size
164 aux = (char *) s;
165 while (*aux)
166 {
167 width--;
168 aux++;
169 }
170
171 // print whitespaces before
172 if (!left_align)
173 while (width > 0)
174 {
175 putch(' ');
176 width--;
177 }
178
179 // print string chars
180 while (*s)
181 {
182 putch(*s);
183 s++;
184 }
185
186 // print whitespaces after
187 if (left_align)
188 while (width > 0)
189 {
190 putch(' ');
191 width--;
192 }
193
194 break;
195 }
196
197 // %d %i: integer, printed in decimal
198 case 'i':
199 case 'd':
200 {
201 bool negative;
202 int divisor;
203 int value = va_arg(vargs, int);
204
205 width--;
206
207 // treat negative number
208 negative = false;
209 if (value < 0)
210 {
211 value = -value;
212 negative = true;
213 width--;
214 }
215
216 // calculate number of digits to print
217 divisor = 1;
218 while (value / divisor > 9)
219 {
220 divisor *= 10;
221 width--;
222 }
223
224 // print whitespaces before
225 if (!left_align)
226 while (width > 0)
227 {
228 putch(' ');
229 width--;
230 }
231
232 // print number signal
233 if (negative)
234 putch('-');
235
236 // print number digits
237 while (divisor > 0)
238 {
239 putch('0' + value / divisor);
240 value %= divisor;
241 divisor /= 10;
242 }
243
244 // print whitespaces after
245 if (left_align)
246 while (width > 0)
247 {
248 putch(' ');
249 width--;
250 }
251
252 break;
253 }
254
255 // %p: long, printed in hexadecimal
256 case 'p':
257 {
258 unsigned nibble;
259 unsigned long value = va_arg(vargs, unsigned long);
260
261 if (value)
262 {
263 putst("0x");
264 for (int i = 15; i >= 0; i--)
265 {
266 nibble = (value >> (i * 4)) & 0xf;
267 putch("0123456789abcdef"[nibble]);
268 }
269 }
270 else
271 putst("(nil)");
272
273 break;
274 }
275
276 // %? unrecognized
277 default:
278 {
279 putst("%?");
280 }
281 }
282 }
283 // not a placeholder, just print it
284 else
285 {
286 putch(*fmt);
287 }
288
289 // take the next char in format
290 if (*fmt)
291 fmt++;
292 }
293 va_end(vargs);
294 }
295
296 //----------------------------------------------------------------------