PS2SDK
PS2 Homebrew Libraries
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 
57 enum 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 */
78 typedef 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 */
91 static 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 */
135 static 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 
185 int vxprintf(
186  void (*func)(char*buf,int cnt,void*arg),
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 */
665 int xprintf(
666  void (*func)(char*buf,int cnt,void*arg),
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 */
688 struct 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 
693 void __sout(char *, int, void *);
694 #ifdef F___sout
695 void __sout(
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
719 int 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
729 int 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
747 int 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))
758 int 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))
784 struct 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 
791 void __mout(char *, int, void*);
792 
793 #ifdef F___mout
794 /* The xprintf callback function. */
795 void __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
827 char *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
857 char *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
876 int 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
903 int 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 
927 void __fout(char *, int, void *);
928 
929 #ifdef F___fout
930 void __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 */
941 int 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
953 int 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
960 int 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
974 int 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
987 int 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 
1002 extern int _iop_reboot_count;
1003 
1004 static int npm_puts_sema = -1;
1005 static int init = 0;
1006 static SifRpcClientData_t npm_cd;
1007 
1008 static 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  sceSifInitRpc(0);
1029 
1030  while (((res = sceSifBindRpc(&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 
1043 int 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 (sceSifCallRpc(&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
1071 int 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
1087 int 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
1100 int 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
ps2lib_err.h
E_LIB_API_INIT
@ E_LIB_API_INIT
Definition: ps2lib_err.h:68
sysclib.h
s_info
Definition: xprintf.c:78
sio_write
size_t sio_write(void *buf, size_t size)
E_SIF_RPC_CALL
@ E_SIF_RPC_CALL
Definition: ps2lib_err.h:88
t_ee_sema
Definition: kernel.h:193
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
ctype.h
__attribute__
typedef __attribute__
Definition: tlbfunc.c:60
_iop_reboot_count
int _iop_reboot_count
tamtypes.h
stdio.h
s_strargument
Definition: xprintf.c:688
t_SifRpcClientData
Definition: sifrpc-common.h:134