PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
xprintf.c
1/*
2 * xprintf.c from ps2sdk/ee/libc/src adapted to IOP
3 *
4 * Copyright (C) 2007-2009 misfire <misfire@xploderfreax.de>
5 *
6 * Licensed under the Academic Free License version 2.0. See file LICENSE.
7 *
8 * Unfortunately, some sysclib functions like sprintf and vsprintf are broken
9 * (at least on my machine). Therefore, instead of importing them, we define
10 * our own.
11 */
12
13/*
14# _____ ___ ____ ___ ____
15# ____| | ____| | | |____|
16# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
17#-----------------------------------------------------------------------
18# Some portions of this file Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
19# Licenced under Academic Free License version 2.0
20# Review ps2sdk README & LICENSE files for further details.
21#
22# Various *printf functions.
23*/
24
25/* Code borrowed from mysql's xprintf.c, by Richard Hipp */
26/* This xprintf.c file on which this one is based is in public domain. */
27
28#include <stdio.h>
29#include <tamtypes.h>
30#include <ps2lib_err.h>
31/*#include <kernel.h>*/
32#include <sifrpc.h>
33/*#include <fileio.h>*/
34/*#include <string.h>*/
35/*#include <alloc.h>*/
36#include <sysclib.h>
37#include <ctype.h>
38
39#include <stdarg.h>
40#include <stddef.h>
41
42/*#include "sio.h"*/
43
44#include "xprintf.h"
45
46/*
47** The maximum number of digits of accuracy in a floating-point conversion.
48*/
49#define MAXDIG 20
50
51#ifdef F_vxprintf
52/*
53** Conversion types fall into various categories as defined by the
54** following enumeration.
55*/
56
57enum e_type { /* The type of the format field */
58 RADIX, /* Integer types. %d, %x, %o, and so forth */
59 FLOAT, /* Floating point. %f */
60 EXP, /* Exponentional notation. %e and %E */
61 GENERIC, /* Floating or exponential, depending on exponent. %g */
62 SIZE, /* Return number of characters processed so far. %n */
63 STRING, /* Strings. %s */
64 PERCENT, /* Percent symbol. %% */
65 CHAR, /* Characters. %c */
66 ERROR, /* Used to indicate no such conversion type */
67/* The rest are extensions, not normally found in printf() */
68 CHARLIT, /* Literal characters. %' */
69 SEEIT, /* Strings with visible control characters. %S */
70 MEM_STRING, /* A string which should be deleted after use. %z */
71 ORDINAL, /* 1st, 2nd, 3rd and so forth */
72};
73
74/*
75** Each builtin conversion character (ex: the 'd' in "%d") is described
76** by an instance of the following structure
77*/
78typedef struct s_info { /* Information about each format field */
79 int fmttype; /* The format field code letter */
80 int base; /* The base for radix conversion */
81 char *charset; /* The character set for conversion */
82 int flag_signed; /* Is the quantity signed? */
83 char *prefix; /* Prefix on non-zero values in alt format */
84 enum e_type type; /* Conversion paradigm */
85} info;
86
87/*
88** The following table is searched linearly, so it is good to put the
89** most frequently used conversion types first.
90*/
91static info fmtinfo[] = {
92 { 'd', 10, "0123456789", 1, 0, RADIX, },
93 { 's', 0, 0, 0, 0, STRING, },
94 { 'S', 0, 0, 0, 0, SEEIT, },
95 { 'z', 0, 0, 0, 0, MEM_STRING, },
96 { 'c', 0, 0, 0, 0, CHAR, },
97 { 'o', 8, "01234567", 0, "0", RADIX, },
98 { 'u', 10, "0123456789", 0, 0, RADIX, },
99 { 'x', 16, "0123456789abcdef", 0, "x0", RADIX, },
100 { 'X', 16, "0123456789ABCDEF", 0, "X0", RADIX, },
101 { 'r', 10, "0123456789", 0, 0, ORDINAL, },
102 { 'f', 0, 0, 1, 0, FLOAT, },
103 { 'e', 0, "e", 1, 0, EXP, },
104 { 'E', 0, "E", 1, 0, EXP, },
105 { 'g', 0, "e", 1, 0, GENERIC, },
106 { 'G', 0, "E", 1, 0, GENERIC, },
107 { 'i', 10, "0123456789", 1, 0, RADIX, },
108 { 'n', 0, 0, 0, 0, SIZE, },
109 { 'S', 0, 0, 0, 0, SEEIT, },
110 { '%', 0, 0, 0, 0, PERCENT, },
111 { 'b', 2, "01", 0, "b0", RADIX, }, /* Binary notation */
112 { 'p', 16, "0123456789ABCDEF", 0, "x0", RADIX, }, /* Pointers */
113 { '\'', 0, 0, 0, 0, CHARLIT, }, /* Literal char */
114};
115#define NINFO (sizeof(fmtinfo)/sizeof(info)) /* Size of the fmtinfo table */
116
117/*
118** If NOFLOATINGPOINT is defined, then none of the floating point
119** conversions will work.
120*/
121#ifndef NOFLOATINGPOINT
122/*
123** "*val" is a double such that 0.1 <= *val < 10.0
124** Return the ascii code for the leading digit of *val, then
125** multiply "*val" by 10.0 to renormalize.
126**
127** Example:
128** input: *val = 3.14159
129** output: *val = 1.4159 function return = '3'
130**
131** The counter *cnt is incremented each time. After counter exceeds
132** 16 (the number of significant digits in a 64-bit float) '0' is
133** always returned.
134*/
135static int getdigit(long double *val, int *cnt){
136 int digit;
137 long double d;
138 if( (*cnt)++ >= MAXDIG ) return '0';
139 digit = (int)*val;
140 d = digit;
141 digit += '0';
142 *val = (*val - d)*10.0;
143 return digit;
144}
145#endif
146
147/*
148** Setting the size of the BUFFER involves trade-offs. No %d or %f
149** conversion can have more than BUFSIZE characters. If the field
150** width is larger than BUFSIZE, it is silently shortened. On the
151** other hand, this routine consumes more stack space with larger
152** BUFSIZEs. If you have some threads for which you want to minimize
153** stack space, you should keep BUFSIZE small.
154*/
155#define BUFSIZE 100 /* Size of the output buffer */
156
157/*
158** The root program. All variations call this core.
159**
160** INPUTS:
161** func This is a pointer to a function taking three arguments
162** 1. A pointer to the list of characters to be output
163** (Note, this list is NOT null terminated.)
164** 2. An integer number of characters to be output.
165** (Note: This number might be zero.)
166** 3. A pointer to anything. Same as the "arg" parameter.
167**
168** arg This is the pointer to anything which will be passed as the
169** third argument to "func". Use it for whatever you like.
170**
171** fmt This is the format string, as in the usual print.
172**
173** ap This is a pointer to a list of arguments. Same as in
174** vfprint.
175**
176** OUTPUTS:
177** The return value is the total number of characters sent to
178** the function "func". Returns -1 on a error.
179**
180** Note that the order in which automatic variables are declared below
181** seems to make a big difference in determining how fast this beast
182** will run.
183*/
184
185int vxprintf(func,arg,format,ap)
186 void (*func)(char*,int,void*);
187 void *arg;
188 const char *format;
189 va_list ap;
190{
191 register const char *fmt; /* The format string. */
192 register int c; /* Next character in the format string */
193 register char *bufpt; /* Pointer to the conversion buffer */
194 register int precision; /* Precision of the current field */
195 register int length; /* Length of the field */
196 register int idx; /* A general purpose loop counter */
197 int count; /* Total number of characters output */
198 int width; /* Width of the current field */
199 int flag_leftjustify; /* True if "-" flag is present */
200 int flag_plussign; /* True if "+" flag is present */
201 int flag_blanksign; /* True if " " flag is present */
202 int flag_alternateform; /* True if "#" flag is present */
203 int flag_zeropad; /* True if field width constant starts with zero */
204 int flag_long; /* True if "l" flag is present */
205 int flag_center; /* True if "=" flag is present */
206 unsigned long longvalue; /* Value for integer types */
207
208#ifndef NOFLOATINGPOINT
209 long double realvalue; /* Value for real types */
210#endif
211 info *infop; /* Pointer to the appropriate info structure */
212 char buf[BUFSIZE]; /* Conversion buffer */
213 char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
214 int errorflag = 0; /* True if an error is encountered */
215 enum e_type xtype; /* Conversion paradigm */
216 char *zMem = 0; /* String to be freed */
217 static char spaces[] =
218 " ";
219#define SPACESIZE (sizeof(spaces)-1)
220#ifndef NOFLOATINGPOINT
221 int exp; /* exponent of real numbers */
222 long double rounder; /* Used for rounding floating point values */
223 int flag_dp; /* True if decimal point should be shown */
224 int flag_rtz; /* True if trailing zeros should be removed */
225 int flag_exp; /* True to force display of the exponent */
226 int nsd; /* Number of significant digits returned */
227#endif
228
229 fmt = format; /* Put in a register for speed */
230 count = length = 0;
231 bufpt = 0;
232 for(; (c=(*fmt))!=0; ++fmt){
233 if( c!='%' ){
234 register int amt;
235 bufpt = (char *)fmt;
236 amt = 1;
237 while( (c=(*++fmt))!='%' && c!=0 ) amt++;
238 (*func)(bufpt,amt,arg);
239 count += amt;
240 if( c==0 ) break;
241 }
242 if( (c=(*++fmt))==0 ){
243 errorflag = 1;
244 (*func)("%",1,arg);
245 count++;
246 break;
247 }
248 /* Find out what flags are present */
249 flag_leftjustify = flag_plussign = flag_blanksign =
250 flag_alternateform = flag_zeropad = flag_center = 0;
251 do{
252 switch( c ){
253 case '-': flag_leftjustify = 1; c = 0; break;
254 case '+': flag_plussign = 1; c = 0; break;
255 case ' ': flag_blanksign = 1; c = 0; break;
256 case '#': flag_alternateform = 1; c = 0; break;
257 case '0': flag_zeropad = 1; c = 0; break;
258 case '=': flag_center = 1; c = 0; break;
259 default: break;
260 }
261 }while( c==0 && (c=(*++fmt))!=0 );
262 if( flag_center ) flag_leftjustify = 0;
263 /* Get the field width */
264 width = 0;
265 if( c=='*' ){
266 width = va_arg(ap,int);
267 if( width<0 ){
268 flag_leftjustify = 1;
269 width = -width;
270 }
271 c = *++fmt;
272 }else{
273 while( isdigit(c) ){
274 width = width*10 + c - '0';
275 c = *++fmt;
276 }
277 }
278 if( width > BUFSIZE-10 ){
279 width = BUFSIZE-10;
280 }
281 /* Get the precision */
282 if( c=='.' ){
283 precision = 0;
284 c = *++fmt;
285 if( c=='*' ){
286 precision = va_arg(ap,int);
287#ifndef COMPATIBILITY
288 /* This is sensible, but SUN OS 4.1 doesn't do it. */
289 if( precision<0 ) precision = -precision;
290#endif
291 c = *++fmt;
292 }else{
293 while( isdigit(c) ){
294 precision = precision*10 + c - '0';
295 c = *++fmt;
296 }
297 }
298 /* Limit the precision to prevent overflowing buf[] during conversion */
299 if( precision>BUFSIZE-40 ) precision = BUFSIZE-40;
300 }else{
301 precision = -1;
302 }
303 /* Get the conversion type modifier */
304 if( c=='l' ){
305 flag_long = 1;
306 c = *++fmt;
307 }else{
308 flag_long = 0;
309 }
310 /* Fetch the info entry for the field */
311 infop = 0;
312 for(idx=0; (unsigned int)idx<NINFO; idx++){
313 if( c==fmtinfo[idx].fmttype ){
314 infop = &fmtinfo[idx];
315 break;
316 }
317 }
318 /* No info entry found. It must be an error. */
319 if( infop==0 ){
320 xtype = ERROR;
321 }else{
322 xtype = infop->type;
323 }
324
325 /*
326 ** At this point, variables are initialized as follows:
327 **
328 ** flag_alternateform TRUE if a '#' is present.
329 ** flag_plussign TRUE if a '+' is present.
330 ** flag_leftjustify TRUE if a '-' is present or if the
331 ** field width was negative.
332 ** flag_zeropad TRUE if the width began with 0.
333 ** flag_long TRUE if the letter 'l' (ell) prefixed
334 ** the conversion character.
335 ** flag_blanksign TRUE if a ' ' is present.
336 ** width The specified field width. This is
337 ** always non-negative. Zero is the default.
338 ** precision The specified precision. The default
339 ** is -1.
340 ** xtype The class of the conversion.
341 ** infop Pointer to the appropriate info struct.
342 */
343 switch( xtype ){
344 case ORDINAL:
345 case RADIX:
346 if(( flag_long )&&( infop->flag_signed )){
347 signed long t = va_arg(ap,signed long);
348 longvalue = t;
349 }else if(( flag_long )&&( !infop->flag_signed )){
350 unsigned long t = va_arg(ap,unsigned long);
351 longvalue = t;
352 }else if(( !flag_long )&&( infop->flag_signed )){
353 signed int t = va_arg(ap,signed int) & ((unsigned long) 0xffffffff);
354 longvalue = t;
355 }else{
356 unsigned int t = va_arg(ap,unsigned int) & ((unsigned long) 0xffffffff);
357 longvalue = t;
358 }
359#ifdef COMPATIBILITY
360 /* For the format %#x, the value zero is printed "0" not "0x0".
361 ** I think this is stupid. */
362 if( longvalue==0 ) flag_alternateform = 0;
363#else
364 /* More sensible: turn off the prefix for octal (to prevent "00"),
365 ** but leave the prefix for hex. */
366 if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
367#endif
368 if( infop->flag_signed ){
369 if( *(long*)&longvalue<0 ){
370 longvalue = -*(long*)&longvalue;
371 prefix = '-';
372 }else if( flag_plussign ) prefix = '+';
373 else if( flag_blanksign ) prefix = ' ';
374 else prefix = 0;
375 }else prefix = 0;
376 if( flag_zeropad && precision<width-(prefix!=0) ){
377 precision = width-(prefix!=0);
378 }
379 bufpt = &buf[BUFSIZE];
380 if( xtype==ORDINAL ){
381 long a,b;
382 a = longvalue%10;
383 b = longvalue%100;
384 bufpt -= 2;
385 if( a==0 || a>3 || (b>10 && b<14) ){
386 bufpt[0] = 't';
387 bufpt[1] = 'h';
388 }else if( a==1 ){
389 bufpt[0] = 's';
390 bufpt[1] = 't';
391 }else if( a==2 ){
392 bufpt[0] = 'n';
393 bufpt[1] = 'd';
394 }else if( a==3 ){
395 bufpt[0] = 'r';
396 bufpt[1] = 'd';
397 }
398 }
399 {
400 register char *cset; /* Use registers for speed */
401 register int base;
402 cset = infop->charset;
403 base = infop->base;
404 do{ /* Convert to ascii */
405 *(--bufpt) = cset[longvalue%base];
406 longvalue = longvalue/base;
407 }while( longvalue>0 );
408 }
409 length = (int)(&buf[BUFSIZE]-bufpt);
410 if(infop->fmttype == 'p')
411 {
412 precision = 8;
413 flag_alternateform = 1;
414 }
415
416 for(idx=precision-length; idx>0; idx--){
417 *(--bufpt) = '0'; /* Zero pad */
418 }
419 if( prefix ) *(--bufpt) = prefix; /* Add sign */
420 if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
421 char *pre, x;
422 pre = infop->prefix;
423 if( *bufpt!=pre[0] ){
424 for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
425 }
426 }
427
428 length = (int)(&buf[BUFSIZE]-bufpt);
429 break;
430 case FLOAT:
431 case EXP:
432 case GENERIC:
433#ifdef NOFLOATINGPOINT
434 va_arg(ap,double);
435#else
436 realvalue = va_arg(ap,double);
437 if( precision<0 ) precision = 6; /* Set default precision */
438 if( precision>BUFSIZE-10 ) precision = BUFSIZE-10;
439 if( realvalue<0.0 ){
440 realvalue = -realvalue;
441 prefix = '-';
442 }else{
443 if( flag_plussign ) prefix = '+';
444 else if( flag_blanksign ) prefix = ' ';
445 else prefix = 0;
446 }
447 if( infop->type==GENERIC && precision>0 ) precision--;
448 rounder = 0.0;
449#ifdef COMPATIBILITY
450 /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
451 for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
452#else
453 /* It makes more sense to use 0.5 */
454 if( precision>MAXDIG-1 ) idx = MAXDIG-1;
455 else idx = precision;
456 for(rounder=0.5; idx>0; idx--, rounder*=0.1);
457#endif
458 if( infop->type==FLOAT ) realvalue += rounder;
459 /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
460 exp = 0;
461 if( realvalue>0.0 ){
462 int k = 0;
463 while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }
464 while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }
465 while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }
466 while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }
467 if( k>=100 ){
468 bufpt = "NaN";
469 length = 3;
470 break;
471 }
472 }
473 bufpt = buf;
474 /*
475 ** If the field type is GENERIC, then convert to either EXP
476 ** or FLOAT, as appropriate.
477 */
478 flag_exp = xtype==EXP;
479 if( xtype!=FLOAT ){
480 realvalue += rounder;
481 if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
482 }
483 if( xtype==GENERIC ){
484 flag_rtz = !flag_alternateform;
485 if( exp<-4 || exp>precision ){
486 xtype = EXP;
487 }else{
488 precision = precision - exp;
489 xtype = FLOAT;
490 }
491 }else{
492 flag_rtz = 0;
493 }
494 /*
495 ** The "exp+precision" test causes output to be of type EXP if
496 ** the precision is too large to fit in buf[].
497 */
498 nsd = 0;
499 if( xtype==FLOAT && exp+precision<BUFSIZE-30 ){
500 flag_dp = (precision>0 || flag_alternateform);
501 if( prefix ) *(bufpt++) = prefix; /* Sign */
502 if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
503 else for(; exp>=0; exp--) *(bufpt++) = getdigit(&realvalue,&nsd);
504 if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
505 for(exp++; exp<0 && precision>0; precision--, exp++){
506 *(bufpt++) = '0';
507 }
508 while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd);
509 *(bufpt--) = 0; /* Null terminate */
510 if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
511 while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
512 if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
513 }
514 bufpt++; /* point to next free slot */
515 }else{ /* EXP or GENERIC */
516 flag_dp = (precision>0 || flag_alternateform);
517 if( prefix ) *(bufpt++) = prefix; /* Sign */
518 *(bufpt++) = getdigit(&realvalue,&nsd); /* First digit */
519 if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
520 while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd);
521 bufpt--; /* point to last digit */
522 if( flag_rtz && flag_dp ){ /* Remove tail zeros */
523 while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
524 if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
525 }
526 bufpt++; /* point to next free slot */
527 if( exp || flag_exp ){
528 *(bufpt++) = infop->charset[0];
529 if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
530 else { *(bufpt++) = '+'; }
531 if( exp>=100 ){
532 *(bufpt++) = (exp/100)+'0'; /* 100's digit */
533 exp %= 100;
534 }
535 *(bufpt++) = exp/10+'0'; /* 10's digit */
536 *(bufpt++) = exp%10+'0'; /* 1's digit */
537 }
538 }
539 /* The converted number is in buf[] and zero terminated. Output it.
540 ** Note that the number is in the usual order, not reversed as with
541 ** integer conversions. */
542 length = (int)(bufpt-buf);
543 bufpt = buf;
544
545 /* Special case: Add leading zeros if the flag_zeropad flag is
546 ** set and we are not left justified */
547 if( flag_zeropad && !flag_leftjustify && length < width){
548 int i;
549 int nPad = width - length;
550 for(i=width; i>=nPad; i--){
551 bufpt[i] = bufpt[i-nPad];
552 }
553 i = prefix!=0;
554 while( nPad-- ) bufpt[i++] = '0';
555 length = width;
556 }
557#endif
558 break;
559 case SIZE:
560 *(va_arg(ap,int*)) = count;
561 length = width = 0;
562 break;
563 case PERCENT:
564 buf[0] = '%';
565 bufpt = buf;
566 length = 1;
567 break;
568 case CHARLIT:
569 case CHAR:
570 c = buf[0] = (xtype==CHAR ? va_arg(ap,int) : *++fmt);
571 if( precision>=0 ){
572 for(idx=1; idx<precision; idx++) buf[idx] = c;
573 length = precision;
574 }else{
575 length =1;
576 }
577 bufpt = buf;
578 break;
579 case STRING:
580 case MEM_STRING:
581 zMem = bufpt = va_arg(ap,char*);
582 if( bufpt==0 ) bufpt = "(null)";
583 length = strlen(bufpt);
584 if( precision>=0 && precision<length ) length = precision;
585 break;
586 case SEEIT:
587 {
588 int i;
589 int c;
590 char *arg = va_arg(ap,char*);
591 for(i=0; i<BUFSIZE-1 && (c = *arg++)!=0; i++){
592 if( c<0x20 || c>=0x7f ){
593 buf[i++] = '^';
594 buf[i] = (c&0x1f)+0x40;
595 }else{
596 buf[i] = c;
597 }
598 }
599 bufpt = buf;
600 length = i;
601 if( precision>=0 && precision<length ) length = precision;
602 }
603 break;
604 case ERROR:
605 buf[0] = '%';
606 buf[1] = c;
607 errorflag = 0;
608 idx = 1+(c!=0);
609 (*func)("%",idx,arg);
610 count += idx;
611 if( c==0 ) fmt--;
612 break;
613 }/* End switch over the format type */
614 /*
615 ** The text of the conversion is pointed to by "bufpt" and is
616 ** "length" characters long. The field width is "width". Do
617 ** the output.
618 */
619 if( !flag_leftjustify ){
620 register int nspace;
621 nspace = width-length;
622 if( nspace>0 ){
623 if( flag_center ){
624 nspace = nspace/2;
625 width -= nspace;
626 flag_leftjustify = 1;
627 }
628 count += nspace;
629 while( (unsigned int)nspace>=SPACESIZE ){
630 (*func)(spaces,SPACESIZE,arg);
631 nspace -= SPACESIZE;
632 }
633 if( nspace>0 ) (*func)(spaces,nspace,arg);
634 }
635 }
636 if( length>0 ){
637 (*func)(bufpt,length,arg);
638 count += length;
639 }
640 if( xtype==MEM_STRING && zMem ){
641/* Not needed
642 free(zMem);*/
643 }
644 if( flag_leftjustify ){
645 register int nspace;
646 nspace = width-length;
647 if( nspace>0 ){
648 count += nspace;
649 while( (unsigned int)nspace>=SPACESIZE ){
650 (*func)(spaces,SPACESIZE,arg);
651 nspace -= SPACESIZE;
652 }
653 if( nspace>0 ) (*func)(spaces,nspace,arg);
654 }
655 }
656 }/* End for loop over the format string */
657 return errorflag ? -1 : count;
658} /* End of function */
659#endif
660
661#ifdef F_xprintf
662/*
663** This non-standard function is still occasionally useful....
664*/
665int xprintf(
666 void (*func)(char*,int,void*),
667 void *arg,
668 const char *format,
669 ...
670){
671 va_list ap;
672 int ret;
673 va_start(ap,format);
674 ret = vxprintf(func,arg,format,ap);
675 va_end(ap);
676 return ret;
677}
678#endif
679
680/*
681** Now for string-print, also as found in any standard library.
682** Add to this the snprint function which stops added characters
683** to the string at a given length.
684**
685** Note that snprint returns the length of the string as it would
686** be if there were no limit on the output.
687*/
688struct s_strargument { /* Describes the string being written to */
689 char *next; /* Next free slot in the string */
690 char *last; /* Last available slot in the string */
691};
692
693void __sout(char *, int, void *);
694#ifdef F___sout
695void __sout(txt,amt,arg)
696 char *txt;
697 int amt;
698 void *arg;
699{
700 register char *head;
701 register const char *t;
702 register int a;
703 register char *tail;
704 a = amt;
705 t = txt;
706 head = ((struct s_strargument*)arg)->next;
707 tail = ((struct s_strargument*)arg)->last;
708 if( tail ){
709 while( a-- >0 && head<tail ) *(head++) = *(t++);
710 }else{
711 while( a-- >0 ) *(head++) = *(t++);
712 }
713 *head = 0;
714 ((struct s_strargument*)arg)->next = head;
715}
716#endif
717
718#ifdef F_vsnprintf
719int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap){
720 struct s_strargument arg;
721 arg.next = buf;
722 arg.last = &buf[n-1];
723 *buf = 0;
724 return vxprintf(__sout,&arg,fmt,ap);
725}
726#endif
727
728#ifdef F_snprintf
729int snprintf(char *str, size_t sz, const char *format, ...)
730{
731 va_list args;
732 struct s_strargument arg;
733 int ret;
734
735 arg.next = str;
736 arg.last = &str[sz-1];
737
738 va_start(args, format);
739 ret = vxprintf(__sout, &arg, format, args);
740 va_end(args);
741
742 return ret;
743}
744#endif
745
746#ifdef F_vsprintf
747int vsprintf(char *buf, const char *fmt, va_list ap){
748 struct s_strargument arg;
749 arg.next = buf;
750 arg.last = NULL;
751 *buf = 0;
752 return vxprintf(__sout,&arg,fmt,ap);
753}
754#endif
755
756#ifdef F_sprintf
757__attribute__((weak))
758int sprintf (char *str, const char *format, ...)
759{
760 va_list args;
761 struct s_strargument arg;
762 int ret;
763
764 arg.next = str;
765 arg.last = NULL;
766
767 va_start(args, format);
768 ret = vxprintf(__sout, &arg, format, args);
769 va_end(args);
770
771 return ret;
772}
773#endif
774
775/*
776** The following section of code handles the mprintf routine, that
777** writes to memory obtained from malloc().
778*/
779
780/* This structure is used to store state information about the
781** write in progress
782*/
783__attribute__((weak))
784struct sgMprintf {
785 char *zBase; /* A base allocation */
786 char *zText; /* The string collected so far */
787 int nChar; /* Length of the string so far */
788 int nAlloc; /* Amount of space allocated in zText */
789};
790
791void __mout(char *, int, void*);
792
793#ifdef F___mout
794/* The xprintf callback function. */
795void __mout(zNewText,nNewChar,arg)
796 char *zNewText;
797 int nNewChar;
798 void *arg;
799{
800 struct sgMprintf *pM = (struct sgMprintf*)arg;
801 if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
802 pM->nAlloc = pM->nChar + nNewChar*2 + 1;
803 if( pM->zText==pM->zBase ){
804 pM->zText = malloc(pM->nAlloc);
805 if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);
806 }else{
807 pM->zText = realloc(pM->zText, pM->nAlloc);
808 }
809 }
810 if( pM->zText ){
811 memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
812 pM->nChar += nNewChar;
813 pM->zText[pM->nChar] = 0;
814 }
815}
816#endif
817
818/*
819** mprintf() works like printf(), but allocations memory to hold the
820** resulting string and returns a pointer to the allocated memory.
821**
822** We changed the name to TclMPrint() to conform with the Tcl private
823** routine naming conventions.
824*/
825
826#ifdef F_mprintf
827char *mprintf(const char *zFormat, ...){
828 va_list ap;
829 struct sgMprintf sMprintf;
830 char *zNew;
831 char zBuf[200];
832
833 va_start(ap,zFormat);
834 sMprintf.nChar = 0;
835 sMprintf.nAlloc = sizeof(zBuf);
836 sMprintf.zText = zBuf;
837 sMprintf.zBase = zBuf;
838 vxprintf(__mout,&sMprintf,zFormat,ap);
839 va_end(ap);
840 if( sMprintf.zText==sMprintf.zBase ){
841 zNew = malloc( sMprintf.nChar+1 );
842 if( zNew ) strcpy(zNew,zBuf);
843 }else{
844 zNew = realloc(sMprintf.zText,sMprintf.nChar+1);
845 }
846
847 return zNew;
848}
849#endif
850
851/* This is the varargs version of mprintf.
852**
853** The name is changed to TclVMPrintf() to conform with Tcl naming
854** conventions.
855*/
856#ifdef F_vmprintf
857char *vmprintf(const char *zFormat,va_list ap){
858 struct sgMprintf sMprintf;
859 char zBuf[200];
860 sMprintf.nChar = 0;
861 sMprintf.zText = zBuf;
862 sMprintf.nAlloc = sizeof(zBuf);
863 sMprintf.zBase = zBuf;
864 vxprintf(__mout,&sMprintf,zFormat,ap);
865 if( sMprintf.zText==sMprintf.zBase ){
866 sMprintf.zText = malloc( strlen(zBuf)+1 );
867 if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);
868 }else{
869 sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1);
870 }
871 return sMprintf.zText;
872}
873#endif
874
875#ifdef F_asprintf
876int asprintf(char ** strp, const char *zFormat, ...){
877 va_list ap;
878 struct sgMprintf sMprintf;
879 char *zNew;
880 char zBuf[200];
881
882 va_start(ap,zFormat);
883 sMprintf.nChar = 0;
884 sMprintf.nAlloc = sizeof(zBuf);
885 sMprintf.zText = zBuf;
886 sMprintf.zBase = zBuf;
887 vxprintf(__mout,&sMprintf,zFormat,ap);
888 va_end(ap);
889 if( sMprintf.zText==sMprintf.zBase ){
890 zNew = malloc( sMprintf.nChar+1 );
891 if( zNew ) strcpy(zNew,zBuf);
892 }else{
893 zNew = realloc(sMprintf.zText,sMprintf.nChar+1);
894 }
895
896 *strp = zNew;
897
898 return sMprintf.nChar+1;
899}
900#endif
901
902#ifdef F_vasprintf
903int vasprintf(char **strp, const char *format, va_list ap) {
904 struct sgMprintf sMprintf;
905 char zBuf[200];
906 sMprintf.nChar = 0;
907 sMprintf.zText = zBuf;
908 sMprintf.nAlloc = sizeof(zBuf);
909 sMprintf.zBase = zBuf;
910 vxprintf(__mout,&sMprintf,format,ap);
911 if( sMprintf.zText==sMprintf.zBase ){
912 sMprintf.zText = malloc( strlen(zBuf)+1 );
913 if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);
914 }else{
915 sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1);
916 }
917 *strp = sMprintf.zText;
918 return sMprintf.nChar;
919}
920#endif
921
922/*
923** The following section of code handles the standard fprintf routines
924** for pthreads.
925*/
926
927void __fout(char *, int, void *);
928
929#ifdef F___fout
930void __fout(zNewText,nNewChar,arg)
931 char *zNewText;
932 int nNewChar;
933 void *arg;
934{
935 fwrite(zNewText,1,nNewChar,(FILE*)arg);
936}
937#endif
938
939#ifdef F_fprintf
940/* The public interface routines */
941int fprintf(FILE *pOut, const char *zFormat, ...){
942 va_list ap;
943 int retc;
944
945 va_start(ap,zFormat);
946 retc = vxprintf(__fout,pOut,zFormat,ap);
947 va_end(ap);
948 return retc;
949}
950#endif
951
952#ifdef F_vfprintf
953int vfprintf(FILE *pOut, const char *zFormat, va_list ap){
954 return vxprintf(__fout,pOut,zFormat,ap);
955}
956#endif
957
958
959#ifdef F_printf
960int printf(const char *format, ...)
961{
962 va_list args;
963 int ret;
964
965 va_start(args, format);
966 ret = vprintf(format, args);
967 va_end(args);
968
969 return ret;
970}
971#endif
972
973#ifdef F_vprintf
974int vprintf(const char *format, va_list args)
975{
976 static char buf[PS2LIB_STR_MAX];
977 int ret;
978
979 ret = vsnprintf(buf, PS2LIB_STR_MAX, format, args);
980
981 write(1, buf, ret);
982 return ret;
983}
984#endif
985
986#ifdef F_putchar
987int putchar( int chr )
988{
989 write(1, &chr, 1);
990 return chr;
991}
992#endif
993
994/* Napalm puts() and printf() */
995/* Who are still using them anyway? :P */
996
997#ifdef F_npmPuts
998
999#define NPM_RPC_SERVER 0x14d704e
1000#define NPM_RPC_PUTS 1
1001
1002extern int _iop_reboot_count;
1003
1004static int npm_puts_sema = -1;
1005static int init = 0;
1006static SifRpcClientData_t npm_cd;
1007
1008static int npm_puts_init()
1009{
1010 int res;
1011 ee_sema_t sema;
1012 static int _rb_count = 0;
1013 if(_rb_count != _iop_reboot_count)
1014 {
1015 _rb_count = _iop_reboot_count;
1016 init = 0;
1017 }
1018
1019 if(init)
1020 return(0);
1021
1022 sema.init_count = 0;
1023 sema.max_count = 1;
1024 sema.option = 0;
1025 if ((npm_puts_sema = CreateSema(&sema)) < 0)
1026 return -1;
1027
1028 SifInitRpc(0);
1029
1030 while (((res = SifBindRpc(&npm_cd, NPM_RPC_SERVER, 0)) >= 0) &&
1031 (npm_cd.server == NULL))
1032 nopdelay();
1033
1034 if (res < 0)
1035 return res;
1036
1037 SignalSema(npm_puts_sema);
1038
1039 init = 1;
1040 return 0;
1041}
1042
1043int npmPuts(const char *buf)
1044{
1045 u8 puts_buf[512]; /* Implicitly aligned. */
1046 void *p = puts_buf;
1047
1048 if (npm_puts_init() < 0)
1049 return -E_LIB_API_INIT;
1050
1051 WaitSema(npm_puts_sema);
1052
1053 /* If the buffer is already 16-byte aligned, no need to copy it. */
1054 if (((u32)buf & 15) == 0)
1055 p = (void *)buf;
1056 else {
1057 strncpy(p, buf, 511);
1058 ((char *) p)[511] = '\0';
1059 }
1060
1061 if (SifCallRpc(&npm_cd, NPM_RPC_PUTS, 0, p, 512, NULL, 0, NULL, NULL) < 0)
1062 return -E_SIF_RPC_CALL;
1063
1064 SignalSema(npm_puts_sema);
1065
1066 return 1;
1067}
1068#endif
1069
1070#ifdef F_nprintf
1071int nprintf(const char *format, ...)
1072{
1073 char buf[PS2LIB_STR_MAX];
1074 va_list args;
1075 int ret;
1076
1077 va_start(args, format);
1078 ret = vsnprintf(buf, PS2LIB_STR_MAX, format, args);
1079 va_end(args);
1080
1081 npmPuts(buf);
1082 return ret;
1083}
1084#endif
1085
1086#ifdef F_vnprintf
1087int vnprintf(const char *format, va_list args)
1088{
1089 char buf[PS2LIB_STR_MAX];
1090 int ret;
1091
1092 ret = vsnprintf(buf, PS2LIB_STR_MAX, format, args);
1093 npmPuts(buf);
1094
1095 return ret;
1096}
1097#endif
1098
1099#ifdef F_sio_printf
1100int sio_printf(const char *format, ...)
1101{
1102 static char buf[PS2LIB_STR_MAX];
1103 va_list args;
1104 int size;
1105
1106 va_start(args, format);
1107 size = vsnprintf(buf, PS2LIB_STR_MAX, format, args);
1108 va_end(args);
1109
1110 /* A bit hackish, but if the last character is '\n' then strip it off
1111 and pass the string to sio_puts(). */
1112 if (buf[size - 1] == '\n') {
1113 buf[size - 1] = '\0';
1114 size++; /* Account for the '\r'. */
1115 sio_puts(buf);
1116 } else {
1117 sio_write(buf, size);
1118 }
1119
1120 return size;
1121}
1122#endif
@ E_LIB_API_INIT
Definition ps2lib_err.h:68
@ E_SIF_RPC_CALL
Definition ps2lib_err.h:88
size_t sio_write(void *buf, size_t size)
u32 count
start sector of fragmented bd/file