Explorar el Código

Text.Format. Initial Import.

Brucey hace 5 años
padre
commit
3c52e4bc25

+ 27 - 0
format.mod/doc/Clear.bmx

@@ -0,0 +1,27 @@
+SuperStrict
+
+Framework Text.Format
+Import BRL.StandardIO
+
+Local formatter:TFormatter = TFormatter.Create("%2d.   %.2d/%02d/%4d")
+
+Local count:Int = 1
+
+For Local m:Int = 1 To 12
+
+	For Local d:Int = 1 To 21 Step 5
+	
+		' apply the arguments
+		formatter.Arg(count)
+		formatter.Arg(d).Arg(m).Arg(2007)
+	
+		' print the formatted string
+		Print formatter.Format()
+	
+		' reset the arguments
+		formatter.Clear()
+
+		count:+ 1		
+	Next
+
+Next

+ 9 - 0
format.mod/doc/Create.bmx

@@ -0,0 +1,9 @@
+SuperStrict
+
+Framework Text.Format
+Import BRL.StandardIO
+
+Local formatter:TFormatter = TFormatter.Create("Value = %2.1f%%")
+
+Print formatter.Arg(46.4).Format()
+

+ 10 - 0
format.mod/doc/Format.bmx

@@ -0,0 +1,10 @@
+SuperStrict
+
+Framework Text.Format
+Import BRL.StandardIO
+
+Local formatter:TFormatter = TFormatter.Create("->%-10s<->%10s<->%.5s<-")
+
+formatter.Arg("Left").Arg("Right").Arg("Trimmed")
+
+Print formatter.Format()

+ 47 - 0
format.mod/doc/TFormatter.bmx

@@ -0,0 +1,47 @@
+SuperStrict
+
+Framework Text.Format
+Import BRL.StandardIO
+
+' Create a title
+Local title:TFormatter = TFormatter.Create("%-30s %8s   %9s~n")
+title.Arg("Product").Arg("Quantity").Arg("Value")
+
+' print the title
+Print title.Format()
+
+' some data
+Local prods:String[] = ["Keyboard", "Mouse", "10 CDs"]
+Local amounts:Int[] = [4, 10, 15]
+Local prices:Float[] = [12.99, 9.99, 5.50]
+
+' the data formatting
+Local dataFormat:TFormatter = TFormatter.Create("%-30s    %5d   %9.2f")
+
+Local total:Float
+
+' Print the data
+For Local i:Int = 0 Until 3
+
+	' apply the arguments
+	dataFormat.Arg(prods[i])
+	dataFormat.Arg(amounts[i])
+	dataFormat.Arg(prices[i] * amounts[i])
+	
+	total:+ prices[i] * amounts[i]
+	
+	Print dataFormat.Format()
+	
+	' reset the formatter
+	dataFormat.Clear()
+
+Next
+
+Print
+
+' totals
+Local totalFormat:TFormatter = TFormatter.Create("                                  %5s   %9.2f")
+totalFormat.Arg("Total").Arg(total)
+
+Print totalFormat.Format()
+

+ 87 - 0
format.mod/doc/intro.bbdoc

@@ -0,0 +1,87 @@
+<p>
+The <b>Format</b> module is a String formatter using C-style <i>sprintf / printf</i> syntax.
+</p>
+<p>printf syntax is a universally recognized method of formatted strings. This module attempts to implement the most-used conversion specifications.
+</p>
+<h3>Requirements</h3>
+<p>The Format module requires the <b>BaH.RegEx</b> module. It should be available from the same place you found this one.</p>
+<h2>Using the Formatter</h2>
+<p>
+You begin by creating a formatter, using the <a href="#TFormatter">TFormatter</a> type. The <a href="#Create">Create</a> method takes a format String as a parameter. See the syntax guide below for formatting details.
+</p>
+<pre>
+Local formatter:TFormatter = TFormatter.Create("VAT = %2.1f%%")
+</pre>
+<p>
+Each conversion specification expects an argument (with the exception of %n and %%), to which you must supply an appropriate value.<br>
+You do this by calling one of the following methods:<br>
+<a href="#ByteArg">ByteArg</a>, <a href="#ShortArg">ShortArg</a>, <a href="#IntArg">IntArg</a>, <a href="#LongArg">LongArg</a>, <a href="#FloatArg">FloatArg</a>, <a href="#DoubleArg">DoubleArg</a> or <a href="#StringArg">StringArg</a>.
+</p>
+<pre>
+formatter.FloatArg(17.5)
+</pre>
+<p>Since each <b>Arg</b> method returns the TFormatter object, it allows you to tag together a sequence of arguments, like so:</p>
+<pre>
+Local formatter:TFormatter = TFormatter.Create("Name = %s : Id = X%09d")
+formatter.StringArg("William Smith").IntArg(65002)
+</pre>
+<p>
+The <a href="#Format">Format</a> method formats the text using the given arguments, and returns the String result.
+</p>
+<pre>
+Print formatter.format()
+</pre>
+<p>
+To reuse a formatter, you can call the <a href="#Clear">Clear</a> method to remove the arguments, allowing you to apply some new ones without the formatting engine having to re-process the format string.
+</p>
+<h2>A quick guide to syntax</h2>
+<p>The format string can contain both ordinary text and conversion specifications.
+</p>
+<p>A conversion specification begins with a <b>%</b> and ends with a particular conversion specifier (d, f, s, n, %).<br>
+In between, and in the following order, there may be zero or more flags, an optional field width, and an optional precision.
+</p>
+<h3>Flags</h3>
+<p>The % character is followed by zero or more flags :</p>
+<table width="90%" align="center">
+<tr><th>Flag</th><th>Description</th></tr>
+<tr><td><b>#</b></td><td>The value should be converted to an <i>alternate form</i>. For <b>f</b> conversions, the result will always contain a decimal point, even if no digits follow it.<br>
+For other conversions, the result is undefined.</td></tr>
+<tr><td><b>0</b></td><td>The value should be zero padded.<br>
+For <b>d</b> and <b>f</b> conversions, the converted value is padded on the left with zeros rather than blanks.<br>
+For other conversions, the behavior is undefined.</td></tr>
+<tr><td><b>-</b></td><td>The converted value is to be left justified on the field boundary. (The default is right justification.)<br>
+Except for <b>n</b> conversions, the converted value is padded on the right with blanks, rather than on the left with blanks or zeros. A - overrides a 0 if both are given.</td></tr>
+<tr><td><b>' '</b> (space)</td><td>A blank should be left before a positive number (or empty string) produced by a signed conversion.</td></tr>
+<tr><td><b>+</b></td><td>A sign (+ or -) should always be placed before a number produced by a signed conversion. By default a sign is used only for negative numbers. A + overrides a space if both are used.</td></tr>
+<tr><td><b>,</b></td><td>For decimal conversion (<b>d</b>, <b>f</b>) the output is to be grouped with thousands’ grouping character.</td></tr>
+</table>
+<h3>Field width</h3>
+<p> An optional number specifying a minimum field width.<br>
+If  the  converted  value  has fewer characters than the field width, it will be padded with spaces on the left (or right, if the left-justify flag has been given). <br>
+In no case does a non-existent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the field is expanded  to  contain  the  conversion result.
+</p>
+<h3>Precision</h3>
+<p>
+An  optional  precision, in the form of a period ('.') followed by an optional integer value.<br>
+If the precision is given as just '.', or the precision is negative, the precision is taken to be zero.<br>
+This gives the minimum number of digits to appear for <b>d</b> conversions, the number of digits to appear after the radix character for <b>f</b> conversions, or the maximum number of characters to be printed from a string for <b>s</b> conversions.
+</p>
+<h3>Conversion Specifier</h3>
+<p>
+A character that specifies the type of conversion to be applied.  The conversion specifiers and their meanings are:</p>
+<table width="90%" align="center">
+<tr><th>Conversion</th><th>Description</th></tr>
+<tr><td><b>d</b></td><td>The argument (Byte, Short, Int, Long) is converted to signed decimal notation.<br>
+The precision, if any, gives the minimum number of digits that must appear; if the converted value requires fewer digits, it is padded on the left  with zeros.<br>
+The default precision is 1.</td></tr>
+<tr><td><b>f</b></td><td>The argument (Float, Double) is rounded and converted to decimal notation in the  style [-]ddd.ddd,  where  the number  of  digits  after  the decimal-point character is equal to the precision specification.<br>
+If the precision is missing, it is taken as 6; if the precision is explicitly zero, no decimal-point character appears.<br>
+If a decimal point appears, at least one digit appears before it.</td></tr>
+<tr><td><b>s</b></td><td>The argument (String) is converted to a space-padded or left-justified string equal to the width specified.<br>
+If precision is given, no more than the number of characters specified are output.
+</td></tr>
+<tr><td><b>n</b></td><td>The platform specific line-separator.</td></tr>
+<tr><td><b>%</b></td><td>A literal %.</td></tr>
+</table>
+
+

+ 602 - 0
format.mod/format.bmx

@@ -0,0 +1,602 @@
+' Copyright (c) 2007-2020 Bruce A Henderson
+' 
+' Permission is hereby granted, free of charge, to any person obtaining a copy
+' of this software and associated documentation files (the "Software"), to deal
+' in the Software without restriction, including without limitation the rights
+' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+' copies of the Software, and to permit persons to whom the Software is
+' furnished to do so, subject to the following conditions:
+' 
+' The above copyright notice and this permission notice shall be included in
+' all copies or substantial portions of the Software.
+' 
+' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+' THE SOFTWARE.
+' 
+SuperStrict
+
+Rem
+bbdoc: String Formatter
+End Rem
+Module Text.Format
+
+ModuleInfo "Version: 1.03"
+ModuleInfo "License: MIT"
+ModuleInfo "Copyright: 2007-2020 Bruce A Henderson"
+ModuleInfo "Modserver: BRL"
+
+ModuleInfo "History: 1.03"
+ModuleInfo "History: Updated for inclusion into NG/BRL."
+ModuleInfo "History: 1.02"
+ModuleInfo "History: Fixed offset problem."
+ModuleInfo "History: Use StringBuilder/Buffer for string concat."
+ModuleInfo "History: 1.01"
+ModuleInfo "History: Rewritten to use native snfprintf."
+ModuleInfo "History: License change to MIT."
+ModuleInfo "History: 1.00"
+ModuleInfo "History: Initial Release."
+
+
+Import Text.RegEx
+Import BRL.LinkedList
+Import BRL.StringBuilder
+
+Import "glue.c"
+
+Private
+Extern
+	Function bmx_sprintf_string:String(format:Byte Ptr, value:String)
+	Function bmx_sprintf_float:String(format:Byte Ptr, value:Float)
+	Function bmx_sprintf_int:String(format:Byte Ptr, value:Int)
+	Function bmx_sprintf_uint:String(format:Byte Ptr, value:UInt)
+	Function bmx_sprintf_double:String(format:Byte Ptr, value:Double)
+	Function bmx_sprintf_long:String(format:Byte Ptr, value:Long)
+	Function bmx_sprintf_ulong:String(format:Byte Ptr, value:ULong)
+	Function bmx_sprintf_sizet:String(format:Byte Ptr, value:Size_T)
+	Function bmx_sprintf_ptr:String(format:Byte Ptr, value:Byte Ptr)
+End Extern
+Public
+
+Rem
+bbdoc: The string formatter.
+about: Processes printf-style format strings.
+End Rem
+Type TFormatter
+
+	Private
+	Global regex:TRegEx = TRegEx.Create("%(\d+\$)?([-#+ 0,l(\<]*)?(\d+)?(\.\d+)?([a-zA-Z%])")
+	Field Text:String
+	
+	Field formatParts:TStringFormatPart[]
+	Field args:TArg[]
+	Field argCount:Int
+	
+	Public
+	Rem
+	bbdoc: Creates a new #TFormatter object.
+	about: Parameters:
+	<ul>
+	<li><b>text</b> : The text containing formatting instructions</li>
+	</ul>
+	End Rem
+	Function Create:TFormatter(Text:String)
+		Local this:TFormatter = New TFormatter
+		
+		this.Text = Text
+		
+		If Text Then
+			this.parse()
+		End If
+		
+		Return this
+	End Function
+	
+Private	
+	Method parse()
+		Local parts:TList = New TList
+		
+		Local match:TRegExMatch = regex.Find(Text)
+		Local i:Int = 0
+		
+		While i < Text.length
+			
+			If match Then
+				
+				' is there text before the formatting text ?
+				If i <> match.SubStart(0) Then
+
+					parts.addLast(TPlainText.Create(Text[i..match.SubStart(0)]))
+					
+				End If
+
+				' this is the formatting part
+				Local sections:String[] = New String[5]
+				For Local n:Int = 1 Until 6
+					sections[n-1] = match.SubExp(n)
+				Next
+				
+				parts.addLast(TFormattingText.Create(sections))
+				
+			Else
+				' is there text at the end of all the formatting parts?
+				parts.addLast(TPlainText.Create(Text[i..]))
+				
+				Exit
+			End If
+			
+			i = match.SubEnd(0) + 1
+			
+			match = regex.find()
+		Wend
+
+		formatParts = New TStringFormatPart[parts.count()]
+		i = 0
+		For Local part:TStringFormatPart = EachIn parts
+			formatParts[i] = part
+			i:+ 1
+		Next
+		
+	End Method
+
+	Method addArg(arg:TArg)
+		If argCount >= args.length
+			args = args[0..argCount + 4]
+		End If
+		
+		args[argCount] = arg
+		
+		argCount :+ 1
+	End Method
+Public
+
+	Rem
+	bbdoc: Appends a #Byte argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Byte)
+		Local arg:TByteArg = New TByteArg
+		arg.value = value
+		
+		addArg(arg)
+		
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #Short argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Short)
+		Local arg:TShortArg = New TShortArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends an #Int argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Int)
+		Local arg:TIntArg = New TIntArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #UInt argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:UInt)
+		Local arg:TUIntArg = New TUIntArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #Long argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Long)
+		Local arg:TLongArg = New TLongArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+	
+	Rem
+	bbdoc: Appends a #ULong argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:ULong)
+		Local arg:TULongArg = New TULongArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #Float argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Float)
+		Local arg:TFloatArg = New TFloatArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #Double argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Double)
+		Local arg:TDoubleArg = New TDoubleArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #Size_T argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Size_T)
+		Local arg:TSizeTArg = New TSizeTArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a Byte Ptr argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:Byte Ptr)
+		Local arg:TPtrArg = New TPtrArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Appends a #String argument to the formatter.
+	End Rem
+	Method Arg:TFormatter(value:String)
+		Local arg:TStringArg = New TStringArg
+		arg.value = value
+		
+		addArg(arg)
+
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Processes and returns the formatted string.
+	returns: The formatted String.
+	End Rem
+	Method Format:String()
+		Local sb:TStringBuilder = New TStringBuilder
+
+		Local arg:Int = 0
+		
+		If Text Then
+			For Local i:Int = 0 Until formatParts.length
+				Local part:TStringFormatPart = formatParts[i]
+				If TPlainText(part) Then
+					sb.Append(part.ToString())
+				Else
+					Local fpart:TFormattingText = TFormattingText(part)
+					If fpart.formatType = TFormattingText.FTYPE_PERCENT Then
+						sb.Append("%")
+					Else
+						If (Not fpart.invalid) And (args And arg < argCount) Then
+							sb.Append(fpart.processArg(args[arg]))
+							' next arg only if this was a "real" arg format
+							If fpart.formatType <> TFormattingText.FTYPE_LINEBREAK Then
+								arg:+ 1
+							End If
+						Else	
+							If Not fpart.invalid Then
+								sb.Append(fpart.processArg(New TNullArg))
+							Else
+								sb.Append(part.ToString())
+							End If
+						End If
+					End If
+				End If
+			Next
+		End If
+		
+		Return sb.ToString()
+	End Method
+
+	Rem
+	bbdoc: Clears the formatter argument list, ready for new arguments.
+	End Rem
+	Method Clear:TFormatter()
+		For Local i:Int = 0 Until argCount
+			args[i] = Null
+		Next
+		argCount = 0
+		Return Self
+	End Method
+	
+End Type
+
+Private
+Type TStringFormatPart
+	
+	Method ToString:String() Abstract
+End Type
+
+Type TPlainText Extends TStringFormatPart
+
+	Field Text:String
+
+	Function Create:TPlainText(Text:String)
+		Local this:TPlainText = New TPlainText
+		
+		this.Text = Text
+		
+		Return this
+	End Function
+	
+	Method ToString:String()
+		Return Text
+	End Method
+	
+End Type
+
+Type TFormattingText Extends TStringFormatPart
+
+	Const FTYPE_LINEBREAK:Int = 110  ' n
+	Const FTYPE_PERCENT:Int = 37     ' %
+
+	Field sections:String[]
+	Field formatType:Int = 0
+	
+	Field formatText:String
+	Field formatPtr:Byte Ptr
+	
+	Field invalid:Int = False
+	
+	Function Create:TFormattingText(sections:String[])
+		Local this:TFormattingText = New TFormattingText
+		
+		this.sections = sections
+		this.configure()
+		
+		Return this
+	End Function
+
+	Method configure()
+		formatText = "%"
+		For Local i:Int = 0 Until sections.length
+			formatText:+ sections[i]
+		Next
+
+		If formatText = "%%" Then
+			formatType = FTYPE_PERCENT
+		End If
+		formatPtr = formatText.ToCString()
+	End Method
+	
+	Method ProcessArg:String(arg:TArg)
+		Local s:String
+
+		Select arg.ArgType()
+			Case TArg.ARG_STRING
+				s = bmx_sprintf_string(formatText, TStringArg(arg).value)
+			Case TArg.ARG_INT
+				s = bmx_sprintf_int(formatText, TIntArg(arg).value)
+			Case TArg.ARG_UINT
+				s = bmx_sprintf_uint(formatText, TUIntArg(arg).value)
+			Case TArg.ARG_FLOAT
+					s = bmx_sprintf_float(formatText, TFloatArg(arg).value)
+			Case TArg.ARG_DOUBLE
+				s = bmx_sprintf_double(formatText, TDoubleArg(arg).value)
+			Case TArg.ARG_LONG
+				s = bmx_sprintf_long(formatText, TLongArg(arg).value)
+			Case TArg.ARG_ULONG
+				s = bmx_sprintf_ulong(formatText, TULongArg(arg).value)
+			Case TArg.ARG_SIZET
+				s = bmx_sprintf_sizet(formatText, TSizeTArg(arg).value)
+			Case TArg.ARG_SHORT
+				s = bmx_sprintf_int(formatText, Int(TShortArg(arg).value))
+			Case TArg.ARG_BYTE
+				s = bmx_sprintf_int(formatText, Int(TByteArg(arg).value))
+			Case TArg.ARG_PTR
+				s = bmx_sprintf_ptr(formatText, TPtrArg(arg).value)
+		End Select
+
+		Return s
+	End Method
+
+	Method ToString:String()
+		Return "-"
+	End Method
+	
+	Method Delete()
+		If formatPtr Then
+			MemFree(formatPtr)
+			formatPtr = Null
+		End If
+	End Method
+	
+End Type
+
+Type TArg
+	Const ARG_NULL:Int = 0
+	Const ARG_BYTE:Int = 1
+	Const ARG_SHORT:Int = 2
+	Const ARG_INT:Int = 3
+	Const ARG_UINT:Int = 4
+	Const ARG_LONG:Int = 5
+	Const ARG_ULONG:Int = 6
+	Const ARG_FLOAT:Int = 7
+	Const ARG_DOUBLE:Int = 8
+	Const ARG_SIZET:Int = 9
+	Const ARG_STRING:Int = 10
+	Const ARG_PTR:Int = 11
+
+	Method ToString:String() Abstract
+	Method ArgType:Int() Abstract
+End Type
+
+Type TNullArg Extends TArg
+	Method ToString:String()
+		Return Null
+	End Method
+	
+	Method ArgType:Int()
+		Return ARG_NULL
+	End Method
+End Type
+
+Type TByteArg Extends TArg
+	Field value:Byte
+
+	Method ToString:String()
+		Return String.fromInt(Int(value))
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_BYTE
+	End Method
+End Type
+
+Type TShortArg Extends TArg
+	Field value:Short
+
+	Method ToString:String()
+		Return String.fromInt(Int(value))
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_SHORT
+	End Method
+End Type
+
+Type TIntArg Extends TArg
+	Field value:Int
+
+	Method ToString:String()
+		Return String.fromInt(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_INT
+	End Method
+End Type
+
+Type TUIntArg Extends TArg
+	Field value:UInt
+
+	Method ToString:String()
+		Return String.fromUInt(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_UINT
+	End Method
+End Type
+
+Type TFloatArg Extends TArg
+	Field value:Float
+
+	Method ToString:String()
+		Return String.fromFloat(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_FLOAT
+	End Method
+End Type
+
+Type TDoubleArg Extends TArg
+	Field value:Double
+
+	Method ToString:String()
+		Return String.fromDouble(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_DOUBLE
+	End Method
+End Type
+
+Type TStringArg Extends TArg
+	Field value:String
+
+	Method ToString:String()
+		Return value
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_STRING
+	End Method
+End Type
+
+Type TLongArg Extends TArg
+	Field value:Long
+
+	Method ToString:String()
+		Return String.fromLong(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_LONG
+	End Method
+End Type
+
+Type TULongArg Extends TArg
+	Field value:ULong
+
+	Method ToString:String()
+		Return String.fromULong(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_ULONG
+	End Method
+End Type
+
+Type TSizeTArg Extends TArg
+	Field value:Size_T
+
+	Method ToString:String()
+		Return String.fromSizeT(value)
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_SIZET
+	End Method
+End Type
+
+Type TPtrArg Extends TArg
+	Field value:Byte Ptr
+
+	Method ToString:String()
+		Return String.fromSizeT(Size_T(Size_T Ptr(value)))
+	End Method
+
+	Method ArgType:Int()
+		Return ARG_PTR
+	End Method
+End Type

+ 79 - 0
format.mod/glue.c

@@ -0,0 +1,79 @@
+/*
+  Copyright (c) 2007-2018 Bruce A Henderson
+ 
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+  
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+  
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/ 
+
+#include <brl.mod/blitz.mod/blitz.h>
+
+BBString * bmx_sprintf_string(const char * format, BBString * value) {
+	char buffer[2048];
+	char *p = bbStringToUTF8String( value );
+	snprintf(buffer, sizeof(buffer), format, p);
+	bbMemFree( p );
+	return bbStringFromUTF8String(buffer);
+}
+
+BBString * bmx_sprintf_float(const char * format, float value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_int(const char * format, int value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_uint(const char * format, unsigned int value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_double(const char * format, double value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_long(const char * format, BBInt64 value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_ulong(const char * format, BBUInt64 value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_sizet(const char * format, BBSIZET value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}
+
+BBString * bmx_sprintf_ptr(const char * format, void * value) {
+	char buffer[2048];
+	snprintf(buffer, sizeof(buffer), format, value);
+	return bbStringFromCString(buffer);
+}