Author Topic: A very basic printf procedure  (Read 3435 times)

0 Members and 1 Guest are viewing this topic.

Arnold

  • Guest
A very basic printf procedure
« on: June 01, 2015, 12:13:46 PM »
Hi Charles,

I used \examples\DataProcessing\Format1.o2bas to create a printf procedure for some (very) basic C-like formatted output. The code so far is:

Code: OxygenBasic
  1. include "$/inc/console.inc"
  2.  
  3.  
  4.   sub printf(string sf,...)
  5.   '========================
  6.  sys p=@sf+sizeof sys
  7.  
  8.   sys     iv at p 'integers  
  9.  bstring sv at p 'string
  10.  double  dv at p 'double
  11.  float   fv at p 'float
  12.  
  13.   sys i
  14.   string outp=sf
  15.  
  16.   do
  17.     i++ : if i>len(outp) then exit do
  18.    
  19.     select asc outp,i
  20.     case "%"
  21.       if mid(outp,i+1,1) = "s" then  outp=left(outp,i-1) & sv & mid(outp,i+2): p+=sizeof sys
  22.       if mid(outp,i+1,1) = "d" or mid(outp,i+1,1) = "i" then  
  23.          outp=left(outp,i-1) & str(iv) & mid(outp,i+2): p+=sizeof sys
  24.       end if              
  25.       if mid(outp,i+1,1) = "f" then outp=left(outp,i-1) + str(fv) + mid(outp,i+2): p+=sizeof float
  26.       if mid(outp,i+1,1) = "g" then outp=left(outp,i-1) + str(dv) + mid(outp,i+2): p+=sizeof double
  27.          
  28.     end select
  29.   end do
  30.  
  31.   'replace \n
  32.  do
  33.     i=instr(outp,"\n")
  34.     if i then
  35.       outp=left(outp,i-1)+chr(10)+mid(outp,i+2)
  36.     else
  37.       exit do
  38.     end if
  39.   end do
  40.    
  41.   print outp
  42.   end sub
  43.  
  44.  
  45.   'TEST
  46.  '====
  47. printf("A very basic printf procedure\n", "and therefore not foolproof")
  48. printf("not %d% safe\n", 100)
  49. printf(42)
  50. printf("\n%d\n",1+3)
  51. printf "The Eiffel Tower is located in %s\nand it's height is %d ft.\n", "Paris", 986
  52. printf("Pi = %s\n", str(pi,3))
  53.  
  54. float x=1.5f
  55. double x1= x
  56. printf ("x = %f\n", x)
  57. printf ("x = %g", x)    'false
  58. printf ("\nx1 = %g\n", x1)
  59. printf ("100 = hex %s\n", hex(100) )
  60.  
  61. print "Enter ...": waitkey()
  62.  
  63.  

Can this code be optimized in some way? I would only need some basic modifiers, but I am not sure when using e.g. "%f" if it is possible to recognize some different types like float, single, double, quad and treat them differently? In the simplest case I will use "%s" in combination with str(value).


Roland

Charles Pegge

  • Guest
Re: A very basic printf procedure
« Reply #1 on: June 01, 2015, 09:56:00 PM »
Hi Roland,

You can access the real thing:

sprintf_s

Code: OxygenBasic
  1. extern lib "MSVCRT.dll" cdecl
  2. sys  sprintf_s(char *buf, sys size, char *format, ...)
  3. end extern
  4.  

Mike and I had console redirection trouble using printf directly, but you can feed the buffer output of sprintf, wherever it is required.


JRS

  • Guest
Re: A very basic printf procedure
« Reply #2 on: June 01, 2015, 10:27:53 PM »
O2C  8)

Charles Pegge

  • Guest
Re: A very basic printf procedure
« Reply #3 on: June 02, 2015, 02:08:21 AM »
A customised interpretation of sprinf, using byte-wise parsing and a fixed string buffer. Minimises use of temp strings:

Code: OxygenBasic
  1. function sprintf(char* fmt,...) as string
  2. =========================================
  3. indexbase 0
  4. sys    p=@param[1]      'current param pointer
  5. string s=nuls 300       'output buffer
  6. string v                'value string
  7. byte   bs at strptr fmt 'bytes source
  8. byte   bd at strptr s   'bytes dest
  9. sys    id=1             'output buffer index
  10. sys    sy=sizeof sys    'stack width = 4bytes/8bytes
  11. sys lv                  'length of value string
  12. do
  13.   lv=1 'default
  14.  select bs
  15.   case 0
  16.     bd=0
  17.     exit do
  18.   case "%"
  19.     @bs++
  20.     select bs
  21.     case "i"  : int u at p    : v=str(round(u)) : p+=sy : mid(s,id)=v : lv=len v
  22.     case "g"  : float u at p  : v=str(u) : p+=sy : mid(s,id)=v : lv=len v
  23.     case "f"  : double u at p : v=str(u) : p+=sizeof u : mid(s,id)=v : lv=len v
  24.     case "s"  : char u at *p  : p+=sy : mid(s,id)=u : lv=len u
  25.     case else : bd=bs
  26.     end select
  27.   case "\"
  28.     @bs++
  29.     select bs
  30.     case "t"  : bd=9
  31.     case "n"  : bd=10
  32.     case else : bd=bs
  33.     end select
  34.   case else : bd=bs
  35.   end select
  36.   @bs++ : @bd+=lv : id+=lv 'NEXT POSITIONS
  37. end do
  38. return left s,id-1
  39. end function
  40.  
  41. print sprintf "string=%s\ndouble=%f\n","abcdef",-123.45E1
  42.  
« Last Edit: June 03, 2015, 11:22:16 PM by Charles Pegge »

JRS

  • Guest
Re: A very basic printf procedure
« Reply #4 on: June 02, 2015, 02:18:50 AM »
Code: Script BASIC
  1. print format("string=%s\ndouble=%f\n","abcdef",-123.45E1)
  2.  


jrs@laptop:~/sb/sb22/test$ scriba printf.sb
string=abcdef
double=-1234.500000
jrs@laptop:~/sb/sb22/test$


A different approach.

Code: Script BASIC
  1. print "string=abcdef\ndouble=",format("%~-###0.0000\n~",-123.45E1)
  2.  


jrs@laptop:~/sb/sb22/test$ scriba fmt2.sb
string=abcdef
double=-1234.5000
jrs@laptop:~/sb/sb22/test$
« Last Edit: June 02, 2015, 12:11:10 PM by John »

Arnold

  • Guest
Re: A very basic printf procedure
« Reply #5 on: June 03, 2015, 12:43:41 AM »
Hi Charles,

thank you for this piece of code. It is very instructive and it is totally sufficient for my intended use. (using sprintf_s is not essential necessary). I modified the code a little bit to use it as sprintf function and printf procedure:

Code: OxygenBasic
  1. include "$/inc/console.inc"
  2.  
  3. macro do_sprintf(format, ...)
  4. indexbase 0
  5. sys    p=@param[1]      'current param pointer
  6. string s=nuls 300       'output buffer
  7. string v                'value string
  8. byte   bs at strptr fmt 'bytes source
  9. byte   bd at strptr s   'bytes dest
  10. sys    id=1             'output buffer index
  11. sys    sy=sizeof sys    'stack width = 4bytes/8bytes
  12. sys lv                  'length of value string
  13. do
  14.   lv=1 'default
  15.  select bs
  16.   case 0
  17.     bd=0
  18.     exit do
  19.   case "%"
  20.     @bs++
  21.     select bs
  22.     case "i","d" : int u at p : v=str(round(u)) : p+=sy : mid(s,id)=v : lv=len v
  23.     case "g"  : float u at p  : v=str(u) : p+=sy : mid(s,id)=v : lv=len v
  24.     case "f"  : double u at p : v=str(u) : p+=sizeof u : mid(s,id)=v : lv=len v
  25.     case "s"  : char u at *p  : p+=sy : mid(s,id)=u : lv=len u
  26.     case "x"  : char u at *p  : p+=sy : mid(s,id)="0x" & u : lv=len(u)+2  
  27.     case else : bd=bs
  28.     end select
  29.   case "\"
  30.     @bs++
  31.     select bs
  32.     case "t"  : bd=9
  33.     case "n"  : bd=10
  34.     case else : bd=bs
  35.     end select
  36.   case else : bd=bs
  37.   end select
  38.   @bs++ : @bd+=lv : id+=lv 'NEXT POSITIONS
  39. end do
  40. id-=1
  41.  
  42. end macro
  43.  
  44. function sprintf(char* fmt,...) as string
  45. =========================================
  46.    do_sprintf(fmt, ...)
  47.    return left s,id
  48. end function
  49.  
  50.  
  51. sub printf(char* fmt,...)
  52. =========================
  53.    do_sprintf(fmt,...)
  54.    print left s,id
  55. end sub
  56.  
  57. print sprintf "string=%s\ndouble=%f\n","abcdef",-123.45E1
  58. printf "string=%s\ndouble=%f\n","abcdef",-123.45E1
  59.  
  60.   'TEST                    
  61.  '====
  62.  
  63. printf("\nA very basic printf procedure", "and therefore not foolproof")  ' mini joke
  64. printf(`\nnot %d%% "safe"\n`, 100)
  65. printf(42)
  66. printf("\n%d\n",1+3)
  67. printf "The Eiffel Tower is located in %s\nand it's height is %d ft.\n", "Paris", 986
  68. printf "To Pi = %s or not to Pi = %s\n", str(pi,3), str(-pi,4)
  69.  
  70. float x=1.5f
  71. double x1= x
  72. printf ("x = %g\n", x)
  73. printf ("false x = %f", x) ' false
  74. printf ("\ncorrect x1 = %f\n", x1)
  75. printf ("10011 = hex %x\n", hex 10011 )
  76. printf ("The End\n")
  77.  
  78. print "Enter ...": waitkey()
  79.  

this works quite nice and I will use printf in the remaining test cases of Iup 3.14.

Roland

.
« Last Edit: June 03, 2015, 01:05:33 AM by Arnold »

JRS

  • Guest
Re: A very basic printf procedure
« Reply #6 on: June 03, 2015, 08:57:52 AM »
Nice job Roland & Charles!

That is going to make IUP in O2 much easier to use.