Welcome, Guest
You have to register before you can post on our site.

Username
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 92
» Latest member: Andy Dee
» Forum threads: 48
» Forum posts: 285

Full Statistics

Latest Threads
PB 3.5 8-to-7 Bit Text Co...
Forum: Source Code Library
Last Post: Andy Dee
04-03-2025, 10:55 PM
» Replies: 0
» Views: 70
Bug found: →
Forum: PowerBASIC for DOS
Last Post: Andy Dee
03-12-2025, 02:50 PM
» Replies: 5
» Views: 405
$EOF when using Line Inpu...
Forum: PowerBASIC Console Compiler
Last Post: Albert Richheimer
03-12-2025, 08:25 AM
» Replies: 0
» Views: 114
The LeapYear
Forum: Programming
Last Post: Dale Yarker
03-09-2025, 09:18 PM
» Replies: 11
» Views: 678
Leap days (or not) in Feb...
Forum: Source Code Library
Last Post: Andy Dee
03-09-2025, 05:05 PM
» Replies: 2
» Views: 229
Turning http to https?
Forum: Suggestions and discussion about PUMP
Last Post: Andy Dee
03-06-2025, 07:50 PM
» Replies: 2
» Views: 226
PBDOS -- Where The Love A...
Forum: PowerBASIC for DOS
Last Post: Andy Dee
03-06-2025, 01:30 PM
» Replies: 9
» Views: 1,335
2003 Podcast featuring Po...
Forum: This and that - friendly chat
Last Post: Frank Ferrell
02-22-2025, 09:08 PM
» Replies: 0
» Views: 110
Promoting PowerBASIC docu...
Forum: PowerBASIC Documentation
Last Post: Frank Ferrell
02-10-2025, 02:02 AM
» Replies: 3
» Views: 760
Calling opcode string dis...
Forum: Programming
Last Post: Charles Pegge
02-06-2025, 06:42 AM
» Replies: 25
» Views: 2,298

 
  PB 3.5 8-to-7 Bit Text Compression
Posted by: Andy Dee - 04-03-2025, 10:55 PM - Forum: Source Code Library - No Replies

Hello everyone, 
I developed a method to compress short texts by reducing 8-bit characters to 7-bit. While the compression ratio is low for large files, it efficiently reduces small strings. 

Key Steps

  1. Normalization: The input text is restricted to 7-bit ASCII (32–127).
  2. Offset Adjustment: Each character is decremented by 32 to fit within 0–95. 
  3. Compression
    For every 8 bytes, extract bits 0–6 (discarding bit 7).Pack these 7-bit segments into 7 bytes, using all 8 bits per byte. 
  4. Remaining Bytes: If the text length isn’t a multiple of 8, the last 1–7 bytes are copied uncompressed.
  5. Decompression
    Reverse the process: Expand 7-bit segments to 8 bits, then increment by 32. 

Here is the code, including some testing:

Code:
$Compile exe
$Dim All
$Lib All Off
$Error All Off
$String 2
$Com 0
$Float Procedure
$Optimize Size'Speed
$Cpu 80386
$Sound 1
$Stack 1536


'----------------------------------------------------------------------------
' Packe limitierten Text von 8 auf 7 Bit.
' Nutze dafür Zeiger zum Erhöhen der Geschwindigkeit
Declare _
FUNCTION PackTxt87 (sQuelle AS STRING) AS STRING
FUNCTION PackTxt87 (sQuelle AS STRING) AS STRING
  ' lokale Variablen
  DIM iQlen  AS LOCAL INTEGER          ' Länge von sQuelle
  DIM Q_ptr  AS LOCAL BYTE PTR         ' Zeichen-Pointer auf sQuelle
  Dim sZiel  As Local String           ' Komprimiertes sZiel
  DIM iZlen  AS LOCAL INTEGER          ' Länge von sZiel
  DIM Z_ptr  AS LOCAL BYTE PTR         ' Zeichen-Pointer auf sZiel
  DIM iZPos  AS LOCAL INTEGER          ' Position in sZiel
  DIM iQPos  AS LOCAL INTEGER          ' Position in sQuelle
  DIM iQLoop AS LOCAL INTEGER          ' Anzahl KompressionsSchleifen
  DIM iKompS AS LOCAL INTEGER          ' Anzahl komprimierbarer Zeichen
  Dim iRest  As Local Integer          ' Anzahl unkomprimierbarer Zeichen
  Dim bWert  As Local Byte             ' ASCII-32-Wert eines Zeichens.
  Dim iBitQ  As Local Integer          ' Aktuelle Bitbosition in sQuelle
  Dim iBitZ  As Local Integer          ' Aktuelle Bitbosition in sZiel
  Dim sTemp  As Local String

                                       '
  iQlen = LEN(sQuelle)                 ' Hole Länge der Quelle

  '--------------------------------------------------------------------------
  ' Fehler 1 abfangen
  If iQlen < 8 Then _                  ' String zu kurz?
    Function = sQuelle: _              ' Gib Original zurück
    Exit Function                      ' und raus

  iQLoop  = Fix(iQlen/8)               ' Hole Anzahl KompressionsSchleifen
  iRest  = iQlen Mod 8                 ' Hole Anzahl unkomprimierbarer Zeichen
  iKompS = iQLoop * 8                  ' Hole Anzahl komprimierbarer Zeichen
  iZlen  = iQLoop * 7 + iRest          ' Hole Länge komprimierten Strings
                                       '
  DECR iQlen                           ' Null-basiert für Pointer
  Q_ptr = STRPTR32( sQuelle )          ' Setze Pointer auf sQuelle

  '--------------------------------------------------------------------------
  ' Fehler 2 abfangen
  For iQPos = 0 To iQlen               ' Überprüfe auf ungültige Zeichen
    IF @Q_ptr[iQPos] < 32 _
      Or @Q_ptr[iQPos] > 159 _
      THEN
      sZiel = sZiel _                  ' sammle diese
            + Chr$(@Q_ptr[iQPos])
    End If
  Next iQPos

  If Len(sZiel) Then _
    Function = "Falsche Quelle: "+sZiel : _
    Exit Function                      ' und gib sie zurück

  sZiel = Repeat$(iZlen,Chr$(0))       ' Platz für Kompression in sZiel

  Z_ptr = STRPTR32( sZiel  )           ' Setze Pointer auf sZiel
  iZPos = 0                            ' Position im Pointer = 0
  iBitQ = 0                            ' Bitbosition in sQuelle auf 0
  iBitZ = 0                            ' Bitbosition in sZiel  auf 0

  DECR iKompS                          ' Null-basiert für Pointer

  '--------------------------------------------------------------------------
  ' Kompression:
  For iQPos = 0 To iKompS              ' Für komprimierbare Zeichen in sQuelle:
                                       ' 1. Schritt:
    bWert = @Q_ptr[iQPos] - 32         ' ASCII-Wert um 32 vermindern, dass
                                       ' ASCII zwischen 0-159 ist
    For iBitQ = 0 To 6                 ' Lies aus sQuelle Bit 0-6

      If Bit(bWert,iBitQ) = 1 Then     ' Schreibe Ziel-Bits 0-7
        Bit Set @Z_ptr[iZPos], iBitZ   '
      Else                             '
        Bit ReSet @Z_ptr[iZPos], iBitZ '
      End If

      If iBitZ < 7 Then                ' Solange in Ziel zwischen Bit 0 und 7
        Incr iBitZ                     ' Nächstes Bit
      Else                             ' sonst
        iBitZ = 0                      ' Bit 0 in
        Incr iZPos                     ' nächstem Zeichen
      End If
    Next iBitQ
  Next iQPos

  iZPos = iZlen-iRest                  ' Setze Zeiger auf erstes unpackbares
                                       ' Zeichen
  For iQPos = iQlen-iRest+1 To iQlen   ' Für unpackbare Zeichen in sQuelle
    @Z_ptr[iZPos] = @Q_ptr[iQPos]      ' Schreibe unpackbare Zeichen
    Incr iZPos
  Next iQPos


  Function = sZiel

END FUNCTION


'----------------------------------------------------------------------------
' EntPacke limitierten Text von 8 auf 7 Bit.
' Nutze dafür Zeiger zum Erhöhen der Geschwindigkeit
Declare _
FUNCTION DePackTxt87 (sQuelle AS STRING) AS STRING
FUNCTION DePackTxt87 (sQuelle AS STRING) AS STRING
  ' lokale Variablen
  DIM iQlen  AS LOCAL INTEGER          ' Länge von sQuelle
  DIM Q_ptr  AS LOCAL BYTE PTR         ' Zeichen-Pointer auf sQuelle
  Dim sZiel  As Local String           ' Komprimiertes sZiel
  DIM iZlen  AS LOCAL INTEGER          ' Länge von sZiel
  DIM Z_ptr  AS LOCAL BYTE PTR         ' Zeichen-Pointer auf sZiel
  DIM iZPos  AS LOCAL INTEGER          ' Position in sZiel
  DIM iQPos  AS LOCAL INTEGER          ' Position in sQuelle
  DIM iQLoop AS LOCAL INTEGER          ' Anzahl KompressionsSchleifen
  DIM iKompS AS LOCAL INTEGER          ' Anzahl komprimierbarer Zeichen
  Dim iRest  As Local Integer          ' Anzahl unkomprimierbarer Zeichen
  Dim bWert  As Local Byte             ' ASCII-32-Wert eines Zeichens.
  Dim iBitQ  As Local Integer          ' Aktuelle Bitbosition in sQuelle
  Dim iBitZ  As Local Integer          ' Aktuelle Bitbosition in sZiel
  Dim sTemp  As Local String
  Dim bPack  As Local Byte             ' Gepackte Bytes an sQuelleEnde

  iQlen = LEN(sQuelle)                 ' Hole Länge der Quelle

  '--------------------------------------------------------------------------
  ' Fehler 1 abfangen
  If iQlen < 7 Then _                  ' String zu kurz?
    Function = sQuelle: _              ' Gib Original zurück
    Exit Function                      ' und raus

  Q_ptr = STRPTR32( sQuelle )          ' Setze Pointer auf sQuelle

  iQLoop  = Fix(iQlen/7)               ' Hole Anzahl EntPacksSchleifen
  iRest  = iQlen Mod 7                 ' Anzahl ungepackte Zeichen?

  '--------------------------------------------------------------------------
  ' Fehler 2 abfangen

If iRest = 0 Then                      ' Scheint alles gepackt zu sein, dann
  bPack = 0                            ' GePacktes = 0
  For iQPos = iQlen - 7 To iQlen-1     ' Überprfe letzte 7 Zeichen auf
    IF @Q_ptr[iQPos] < 32 _            ' komprimierte Zeichen
      Or @Q_ptr[iQPos] > 127 _         ' Wenn welche da, dann
      THEN Incr bPack                  ' Erhöhe Gepacktes (bPack)
  Next iQPos
End If


  If bPack = 0? _                      ' Wenn keine gepackten Zeichen (bPack)
    And iRest = 0 _                    ' und keine ungepackten Zeichen (iRest)
    Then                               ' dann
    iRest = 7                          ' ungepackte Zeichen (iRest) = 7
    iKompS = iQlen - iRest             ' Setze Anzahl entpackbarer Zeichen
  Else                                 ' sonst
    iKompS = iQLoop * 7                ' Setze Anzahl entpackbarer Zeichen
  End If


  If IsFalse(bPack) _                  ' Sind die iRest-lichen Zeichen
    And iRest = 7 _                    ' ungepackt, dann reduziere
    Then Decr iQLoop                   ' die Anzahl der Entpackaufrufe


  iZlen  = iQLoop * 8 + iRest          ' Hole Länge komprimierten Strings
                                       '
  DECR iQlen                           ' Null-basiert für Pointer

  sZiel = Repeat$(iZlen,Chr$(0))       ' Platz für Kompression in sZiel

  Z_ptr = STRPTR32( sZiel  )           ' Setze Pointer auf sZiel
  iZPos = 0                            ' Position im Pointer = 0
  iBitQ = 0                            ' Bitbosition in sQuelle auf 0
  iBitZ = 0                            ' Bitbosition in sZiel  auf 0

  '--------------------------------------------------------------------------
  ' DeKompression: Rechne Zeichen in sQuelle auf ASCII 32-159 um
  For iQPos = 0 To iKompS              ' Fr entkomprimierbare Zeichen in sQuelle:
                                       ' 1. Schritt:
    For iBitQ = 0 To 7                 ' Lies aus sQuelle Bit 0-7

      If Bit(@Q_ptr[iQPos],iBitQ) = 1 Then ' Schreibe Ziel-Bits 0-7
        Bit Set @Z_ptr[iZPos], iBitZ   '
      Else                             '
        Bit ReSet @Z_ptr[iZPos], iBitZ '
      End If

      If iBitZ < 6 Then                ' Solange in Ziel zwischen Bit 0 und 6
        Incr iBitZ                     ' Nächstes Bit
      Else                             ' sonst
        iBitZ = 0                      ' Bit 0
        Incr @Z_ptr[iZPos], 32         ' Erstelle das richtige ZielZeichen
        Incr iZPos                     ' und nächstes ZielZeichen
      End If

    Next iBitQ

  Next iQPos

  iZPos = iZlen-iRest                  ' Setze Zeiger auf erstes unpackbares
                                       ' Zeichen
  For iQPos = iQlen-iRest+1 To iQlen   ' Für ungepackte Zeichen in sQuelle
    @Z_ptr[iZPos] = @Q_ptr[iQPos]      ' Schreibe ungepackte Zeichen
    Incr iZPos
  Next iQPos


  Function = sZiel

END FUNCTION


' Test-Code'

DIM originalText AS STRING, _
    compressedText AS STRING, _
    decompressedText AS STRING, _
    iIndex As Integer, _
    iLOrg  As Integer, _
    iLPck  As Integer, _
    iLEpk  As Integer

For iIndex = 07 To 19
  '?
  originalText = Left$("PowerBASIC 3.5 is a wonderful tool for writing fast and usefull programs.",iIndex)

  iLOrg = Len(originalText)
  compressedText = PackTxt87(originalText)
  iLPck = Len(compressedText)
  If Instr(compressedText, "Falsche Quelle: ") = 1 Then ?compressedText:end
  decompressedText = DePackTxt87(compressedText)
  iLEpk = Len(decompressedText)
  'PRINT "Original:      ";
  PRINT "Original: ";
  Print originalText;
  $If 0
  Print " ist =";iLOrg;" Byte lang"
  PRINT "Komprimiert:  ";
  Print compressedText;
  Print " ist =";iLPck;" Byte lang"
  PRINT "Dekomprimiert: ";
  Print decompressedText;
  Print " ist =";iLEpk;" Byte lang"
  $EndIf
  ? " --> Test verlief: [erfolg";
  If originalText = decompressedText Then
    Print "reich] :-)  :";iLOrg;iLPck;iLEpk
  Else
  Print "los] ;-(";iLOrg;iLPck;iLEpk
  ?"Original und wieder Entpacktes unterscheiden sich an folgenden Stellen:"
  For iIndex = 1 To iLOrg
    If ASCII(originalText,iIndex) <> ASCII(decompressedText,iIndex) Then
        ?"Position";iIndex;" - Zeichen Original: ";Chr$(ASCII(originalText,iIndex)); _
        " - Zeichen Entpackt: ";Chr$(ASCII(decompressedText,iIndex))
      End If
    Next iIndex
  End If

Next iIndex

Sleep

originalText = "PowerBASIC 3.5 is a wonderful tool for writing fast, small and usefull programs under DOS."
iLOrg = Len(originalText)
compressedText = PackTxt87(originalText)
iLPck = Len(compressedText)
If Instr(compressedText, "Falsche Quelle: ") = 1 Then ?compressedText:end
decompressedText = DePackTxt87(compressedText)
iLEpk = Len(decompressedText)
 
  PRINT "Original:"
  Print originalText;
  ? " --> Test verlief: [erfolg";
  If originalText = decompressedText Then
    Print "reich] :-)  :";iLOrg;iLPck;iLEpk
  Else
  Print "los] ;-(";iLOrg;iLPck;iLEpk
  ?"Original und wieder Entpacktes unterscheiden sich an folgenden Stellen:"
  For iIndex = 1 To iLOrg
    If ASCII(originalText,iIndex) <> ASCII(decompressedText,iIndex) Then
        ?"Position";iIndex;" - Zeichen Original: ";Chr$(ASCII(originalText,iIndex)); _
        " - Zeichen Entpackt: ";Chr$(ASCII(decompressedText,iIndex))
      End If
    Next iIndex
  End If
 
  PRINT "Komprimiert:"
  Print compressedText
  Print "ist =";iLPck;" Byte lang"
  PRINT "Dekomprimiert:"
  Print decompressedText
  Print "ist =";iLEpk;" Byte lang"



originalText = "PowerBASIC 3.5 ist ein wundervolles Werkzeug fr schnelle, kleine bis groáe und vor allen ¯ntzliche® Programme unter DOS."
?originalText
iLOrg = Len(originalText)
compressedText = PackTxt87(originalText)
iLPck = Len(compressedText)
If Instr(compressedText, "Falsche Quelle: ") = 1 Then ?compressedText:end
decompressedText = DePackTxt87(compressedText)
iLEpk = Len(decompressedText)
 
  PRINT "Original:"
  Print originalText;
  ? " --> Test verlief: [erfolg";
  If originalText = decompressedText Then
    Print "reich] :-)  :";iLOrg;iLPck;iLEpk
  Else
  Print "los] ;-(";iLOrg;iLPck;iLEpk
  ?"Original und wieder Entpacktes unterscheiden sich an folgenden Stellen:"
  For iIndex = 1 To iLOrg
    If ASCII(originalText,iIndex) <> ASCII(decompressedText,iIndex) Then
        ?"Position";iIndex;" - Zeichen Original: ";Chr$(ASCII(originalText,iIndex)); _
        " - Zeichen Entpackt: ";Chr$(ASCII(decompressedText,iIndex))
      End If
    Next iIndex
  End If
 
  PRINT "Komprimiert:"
  Print compressedText
  Print "ist =";iLPck;" Byte lang"
  PRINT "Dekomprimiert:"
  Print decompressedText
  Print "ist =";iLEpk;" Byte lang"


This is the DOS-output:
Code:
Original: PowerBA --> Test verlief: [erfolgreich] :-)  : 7  7  7
Original: PowerBAS --> Test verlief: [erfolgreich] :-)  : 8  7  8
Original: PowerBASI --> Test verlief: [erfolgreich] :-)  : 9  8  9
Original: PowerBASIC --> Test verlief: [erfolgreich] :-)  : 10  9  10
Original: PowerBASIC  --> Test verlief: [erfolgreich] :-)  : 11  10  11
Original: PowerBASIC 3 --> Test verlief: [erfolgreich] :-)  : 12  11  12
Original: PowerBASIC 3. --> Test verlief: [erfolgreich] :-)  : 13  12  13
Original: PowerBASIC 3.5 --> Test verlief: [erfolgreich] :-)  : 14  13  14
Original: PowerBASIC 3.5  --> Test verlief: [erfolgreich] :-)  : 15  14  15
Original: PowerBASIC 3.5 i --> Test verlief: [erfolgreich] :-)  : 16  14  16
Original: PowerBASIC 3.5 is --> Test verlief: [erfolgreich] :-)  : 17  15  17
Original: PowerBASIC 3.5 is  --> Test verlief: [erfolgreich] :-)  : 18  16  18
Original: PowerBASIC 3.5 is a --> Test verlief: [erfolgreich] :-)  : 19  17  19

Original:PowerBASIC 3.5 is a wonderful tool for writing fast, small and usefull
programs under DOS. --> Test verlief: [erfolgreich] :-)  : 90  79  90
Komprimiert:
░τ╡(§àf⌐◄`Γ¿ ÆS@►p}:ëE⌐▒╩♦PƒO&└°ö☻«╥$5Θ<☻î┴)ò☺ÿ6âL& Φ$☻¬╙ó▒╩d☻á╥τQ→lN☺U'▒(♣É^S.
ist = 79  Byte lang
Dekomprimiert:
PowerBASIC 3.5 is a wonderful tool for writing fast, small and usefull programs
under DOS.
ist = 90  Byte lang
PowerBASIC 3.5 ist ein wundervolles Werkzeug für schnelle, kleine bis große und
vor allen »nützliche« Programme unter DOS.
Falsche Quelle: ß»« 

Perhaps the code will also be of use to others...

Print this item

  $EOF when using Line Input#
Posted by: Albert Richheimer - 03-12-2025, 08:25 AM - Forum: PowerBASIC Console Compiler - No Replies

Source code moved from PB DOS over here, in reply to @Andy Dee:

Code:
#compile exe
#dim all

function pbmain () as long
    local hFile as long
    local sFile as string
    local sTemp as string

    '
    ' Setup strings
    ' -------------
    '
    sTemp = "ABCDEF" + $EOF + "abcdef"
    sFile = "Data.txt"

    '
    ' Create Data.txt
    ' ---------------
    '
    hFile = freefile
    open sFile for output as #hFile
    print #hFile,sTemp;
    close #hFile

    '
    ' Read Data.txt using get$
    ' ------------------------
    '
    hFile = freefile
    open sFile for binary as #hFile
    get$ #hFile,lof(hFile),sTemp
    close #hFile
    stdout "Using get$:        "+sTemp

    '
    ' Read Data.txt using line input#
    ' -------------------------------
    '
    hFile = freefile
    open sFile for input as #hFile
    line input #hFile,sTemp
    close #hFile
    stdout "Using line input#: "+sTemp

    '
    ' Clean up
    ' --------
    '
    kill sFile

end function

Print this item

  Leap days (or not) in February for PBDOS
Posted by: Dale Yarker - 03-08-2025, 08:48 AM - Forum: Source Code Library - Replies (2)

'DECLARE not needed if FUNCTION source is before the CALL
'here the CALL is in PBMAIN
'I call it bottom up because PBMAIN is last and flow goes up
'
'Pretty sure PUSHes and POPs not needed in FUNCTION
'They will be needed to use "inside" code in-line with BASIC
'
'Used PBCC v6 to test. I no longer have PBDOS available.
function Tage_im_Februar(byval iJahr as integer) as integer
  local FebruarTage as integer
  ! push ax
  ! mov FebruarTage, 28&  'not a leap year, pre-set to 28
  ! mov ax, 1582%
  ! cmp ax, iJahr
  ! jge Julian
  ! mov ax, 3%
  ! and ax, iJahr    'conditionally equivalent MOD 4
  ! jz MOD100        '0 is possible leap year
  ! jmp Done
  MOD100:
  ! push bx          'for divisor
  ! push dx          'for high part of dividend, remainder (MOD)
  ! xor dx, dx
  ! mov ax, iJahr
  ! mov bx, 100%
  ! div bx
  ! cmp dx, 0%    'does MOD 100 = 0 ?
  ! pop dx
  ! pop bx
  ! jz MOD400        '0 is possibly not a leap year
  ! jmp Is29Days      'non 0 is a leap year
  MOD400:
  ! and ax, 3%    'EAX has Year\100, so conditionally equivalent MOD 400
  ! jnz Done
  Julian:
  ! mov ax, 3%
  ! and ax, iJahr
  ! jnz Done
  Is29Days:
  ! mov FebruarTage, 29%
  Done:
  ! pop ax
  function = FebruarTage
end function
function pbmain () as long 'put only to demonstrate Tage_im_Februar
  local iJahr as integer
  iJahr = 2000
  print Tage_im_Februar(iJahr); " 2000, divisible by 400, is leap"
  iJahr = 2100
  print Tage_im_Februar(iJahr); " 2100, divisible by 100 not 400, not leap"
  iJahr = 2104
  print Tage_im_Februar(iJahr); " 2104, divisible by 4 not 100, is leap"
  iJahr = 2103
  print Tage_im_Februar(iJahr); " 2103, not divide 4, not leap
  print "julian, did not check rule for prior to Gregorian myself"
  iJahr = 1204
  print Tage_im_Februar(iJahr); " 1204, divisible by 4, is leap
  iJahr = 1201
  print Tage_im_Februar(iJahr)  " 1201, not divisible by 4, not leap
  waitkey$
end function

Print this item

  The LeapYear
Posted by: Andy Dee - 03-07-2025, 04:09 PM - Forum: Programming - Replies (11)

Here, Dale Yarker shows a fast Way to find a Leap Year.

This looks very nice - for 32-Bit Systems.

Programming in 16-Bit PB 3.5  for DOS, I can only make  Cry eyes…  Huh

I use a much slower routine, calculating results for julian and gregorian calendar.

Code:
Declare _
Function iFeb(ByVal iJahr As Integer)        As Integer
Function iFeb(ByVal iJahr As Integer) Public As Integer
  If iJahr < 1582% then
    Function = 29% _
             + ( _
                 ( _
                   iJahr Mod 4% _
                 ) _
                 <> 0% _
               )
  Else
    Function = 29% _
             + ( _
                 ( _
                   iJahr/4 _
                 ) _
                 <> _
                 ( _
                   iJahr\4 _
                 ) _
                 Or _
                 ( _
                   iJahr/100 _
                 ) _
                 = _
                 ( _
                   iJahr\100 _
                 ) _
                 And _
                 ( _
                   iJahr/400 _
                 ) _
                 <> _
                 ( _
                   iJahr\400 _
                 ) _
               )
  End If
End Function

Does someone has an idea, how this could look in 16-Bit-Inline-Asm?

Print this item

  Bug found: →
Posted by: Andy Dee - 03-07-2025, 12:32 PM - Forum: PowerBASIC for DOS - Replies (5)

Hello everyone

In a text block commented out with $If 0 - $EndIF, the control character "→" appears at some point. This causes PB 3.5 to assume that the file ends here, which is acknowledged with error 436 during compilation.
There used to be this bug with the "ü", but it was fixed quite quickly.
Perhaps of interest and use to someone.

Andy

Edit:
Dieser Fehler tritt auch beim Auskommentieren mit "'" oder "Rem" auf.

Edit 2 (sorry for German language):
This error also occurs when commenting out with “'” or “Rem”.

Print this item

  Turning http to https?
Posted by: Andy Dee - 03-06-2025, 01:20 PM - Forum: Suggestions and discussion about PUMP - Replies (2)

Hello to all, especially to the Admin,

do you see a chance, to turn the http://… to a more secure https://… ?

Wish us all the very best,
Andy

Print this item

  2003 Podcast featuring PowerBASIC founder Bob Zale
Posted by: Frank Ferrell - 02-22-2025, 09:08 PM - Forum: This and that - friendly chat - No Replies

Greetings ....

Found this purely by chance ....

From March 24th 2003, a 53-minute podcast interview by PowerBASIC's Bob Zale, as well as PDQ creator Ethan Winer.

The interview can be downloaded as an mp3 audio file -- just click-on the three dots to the right of the playback field and choose DOWNLOAD.

Here's the link -- Net Rocks Podcast: March 24th 2003

Thanx-A-Lot, Frank

Print this item

  New sub-forum and some housekeeping work
Posted by: Albert Richheimer - 01-30-2025, 01:52 PM - Forum: Suggestions and discussion about PUMP - No Replies

Hi @all

Today I have created an new sub-forum Alternatives to PowerBASIC. Here we can discuss alternatives to the PowerBASIC compiler.

Also I have done some housekeeping. You will see the prefix "Moved". I have moved some threads to the proper place. Please take care when creating a new thread. Thank you!

Cheers,
Albert

Print this item

  Detecting VM discussion
Posted by: Anne Wilson - 01-29-2025, 09:52 PM - Forum: PowerBASIC for Windows - No Replies

I have listed some pertinent codes on detecting Virtual Machines, these are :

Detect QEMU Virtual Machine
http://pump.richheimer.de/showthread.php...160#pid160


Detect Hyper-V Virtual Machine
http://pump.richheimer.de/showthread.php...159#pid159

Detect WINE emulator
http://pump.richheimer.de/showthread.php...146#pid146

Detect the Virtual Box Virtual Machine
http://pump.richheimer.de/showthread.php...143#pid143

This thread forms the discussions for these codes, if you encounter detections through
the use of these programs or not able to detect , please let me know.

These VM and emulator are commonly used in the Windows and Linux platforms
by users who can pirate your programs,  therefore detections are vital to
discourage the use of VM to pirate your products. 

Once a VM is detected, just stop the program and exit.  Or  make it GPF 
or do something irrelevant to make it difficult for them to make copies of your programs ?

Print this item

  Detect QEMU Virtual Machine
Posted by: Anne Wilson - 01-29-2025, 09:39 PM - Forum: Source Code Library - No Replies

This program will detect if it is being run in a QEMU  Virtual Machine VM.
Note that hackers will place your programs to run in a VM so that they can
pirate or hack your programs.  

This is to detect whether the user is using a QEMU  VM and to do the 
necessary counter action.   

Please let me know if you encounter issue with this program.

Code:
  ' Detect QEMU.bas


'   This program uses multiple detection methods for QEMU VM to increase accuracy.
'   However, no single method is foolproof, as virtualization environments
'   can be customized or masked by hackers.

    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"

     %KEY_QUERY_VALUE     = &H0001
     %ERROR_SUCCESS       = 0




'============================
  FUNCTION PBMAIN () AS LONG
    IF IsQEMU() THEN
        ? "Running inside a QEMU virtual machine."
    ELSE
        ? "Not running inside a QEMU virtual machine."
    END IF
END FUNCTION





'===============================
'   Detects QEMU VM using several methods
FUNCTION IsQEMU() AS LONG
    LOCAL hqeKey  AS DWORD
    LOCAL dwType  AS DWORD
    LOCAL dwData  AS DWORD
    LOCAL cbData  AS DWORD
    LOCAL qresult AS LONG

  ' Indicator for various QEMU types
    LOCAL tmpQe   AS LONG
    tmpQe = 0

    ' Check for QEMU-specific registry key (System Manufacturer)
    ' HARDWARE\DESCRIPTION\System\BIOS
    qresult = RegOpenKeyEx(%HKEY_LOCAL_MACHINE, hwBios, 0, %KEY_QUERY_VALUE, hqeKey)
    IF qresult = %ERROR_SUCCESS THEN
        cbData = 256
      ' SystemManufacturer
        qresult = RegQueryValueEx(hqeKey, SysManf , 0, dwType, BYVAL VARPTR(dwData), cbData)
         IF qresult = %ERROR_SUCCESS THEN
            'QEMU
            IF INSTR(UCASE$(PEEK$(VARPTR(dwData), cbData)), StQE) > 0 THEN
                tmpQe = 1
            END IF
        END IF
        RegCloseKey hqeKey
    END IF

    IF tmpQe > 0 THEN
       IsQEMU = 1
       EXIT FUNCTION
    END IF


    ' Check for QEMU-specific driver (qxl.sys or virtio drivers)
    ' such as QXL video adapter or VirtIO devices
    ' C:\Windows\System32\drivers\qxl.sys       and
    ' C:\Windows\System32\drivers\vioinput.sys
    IF ISFILE(qxlS ) OR ISFILE(vioinp) THEN
        tmpQe = 2
    END IF

    IF tmpQe > 0 THEN
       IsQEMU = 1
       EXIT FUNCTION
    END IF

    ' Check for QEMU-specific hardware (QXL video or VirtIO devices)
    ' C:\Windows\System32\drivers\qxl.dll    and
    ' C:\Windows\System32\drivers\viostor.sys
    IF ISFILE(stQxl) OR ISFILE(stVio) THEN
        tmpQe = 3
    END IF

    IF tmpQe > 0 THEN
       IsQEMU = 1
       EXIT FUNCTION
    END IF

  ' Not running inside QEMU
    IsQEMU = 0
END FUNCTION





' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
'    C:\Windows\System32\drivers\vioinput.sys
FUNCTION vioinp() AS STRING

  ' Text is 40 bytes excluding the terminating zero

    #REGISTER NONE

    LOCAL src  AS DWORD
    LOCAL dst  AS DWORD
    LOCAL outpt$

    src = CODEPTR(datalabel)

    outpt$ = NUL$(40)
    dst = STRPTR(outpt$)

  ' -------------------
  ' copy data to string
  ' -------------------
    ! mov esi, src
    ! mov edi, dst
    ! mov ecx, 40
    ! rep movsb

    src = CODEPTR(paddlabel)

  ' -----------------------------
  ' xor string data to unique pad
  ' -----------------------------
    ! mov esi, dst
    ! mov ebx, 40
    ! mov edi, src
    ! add esi, ebx
    ! add edi, ebx
    ! neg ebx

  lbl0:
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jnz lbl0

  lbl1:
    FUNCTION = outpt$
    EXIT FUNCTION

  #ALIGN 4
  datalabel:
    ! db 137,244,134,19,90,252,4,157,27,48,199,3,14,247,228,3
    ! db 175,250,190,186,216,209,84,46,134,104,244,174,243,136,210,100
    ! db 103,146,120,43,36,182,157,78,0

  #ALIGN 4
  paddlabel:
    ! db 202,206,218,68,51,146,96,242,108,67,155,80,119,132,144,102
    ! db 194,201,140,230,188,163,61,88,227,26,135,242,133,225,189,13
    ! db 9,226,13,95,10,197,228,61,0

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤



' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
   '  C:\Windows\System32\drivers\qxl.sys
FUNCTION qxlS() AS STRING

  ' Text is 35 bytes excluding the terminating zero

    #REGISTER NONE

    LOCAL src  AS DWORD
    LOCAL dst  AS DWORD
    LOCAL outpt$

    src = CODEPTR(datalabel)

    outpt$ = NUL$(35)
    dst = STRPTR(outpt$)

  ' -------------------
  ' copy data to string
  ' -------------------
    ! mov esi, src
    ! mov edi, dst
    ! mov ecx, 35
    ! rep movsb

    src = CODEPTR(paddlabel)

  ' -----------------------------
  ' xor string data to unique pad
  ' -----------------------------
    ! mov esi, dst
    ! mov ebx, 35
    ! mov edi, src
    ! add esi, ebx
    ! add edi, ebx
    ! neg ebx

  lbl0:
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jnz lbl0

  lbl1:
    FUNCTION = outpt$
    EXIT FUNCTION

  #ALIGN 4
  datalabel:
    ! db 39,193,199,194,34,252,156,45,109,153,235,30,232,30,74,199
    ! db 100,250,27,119,124,175,212,177,7,207,147,66,236,149,73,81
    ! db 143,69,39,0

  #ALIGN 4
  paddlabel:
    ! db 100,251,155,149,75,146,248,66,26,234,183,77,145,109,62,162
    ! db 9,201,41,43,24,221,189,199,98,189,224,30,157,237,37,127
    ! db 252,60,84,0

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤





' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
'C:\Windows\System32\drivers\qxl.dll
FUNCTION stQxl() AS STRING

  ' Text is 35 bytes excluding the terminating zero

    #REGISTER NONE

    LOCAL src  AS DWORD
    LOCAL dst  AS DWORD
    LOCAL outpt$

    src = CODEPTR(datalabel)

    outpt$ = NUL$(35)
    dst = STRPTR(outpt$)

  ' -------------------
  ' copy data to string
  ' -------------------
    ! mov esi, src
    ! mov edi, dst
    ! mov ecx, 35
    ! rep movsb

    src = CODEPTR(paddlabel)

  ' -----------------------------
  ' xor string data to unique pad
  ' -----------------------------
    ! mov esi, dst
    ! mov ebx, 35
    ! mov edi, src
    ! add esi, ebx
    ! add edi, ebx
    ! neg ebx

  lbl0:
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jnz lbl0

  lbl1:
    FUNCTION = outpt$
    EXIT FUNCTION

  #ALIGN 4
  datalabel:
    ! db 107,242,156,222,105,186,235,71,251,111,207,178,223,54,223,160
    ! db 48,66,192,5,85,78,114,228,105,10,125,30,253,8,13,29
    ! db 29,250,74,0

  #ALIGN 4
  paddlabel:
    ! db 40,200,192,137,0,212,143,40,140,28,147,225,166,69,171,197
    ! db 93,113,242,89,49,60,27,146,12,120,14,66,140,112,97,51
    ! db 121,150,38,0

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤


' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
   '   C:\Windows\System32\drivers\viostor.sys
FUNCTION stVio() AS STRING

  ' Text is 39 bytes excluding the terminating zero

    #REGISTER NONE

    LOCAL src  AS DWORD
    LOCAL dst  AS DWORD
    LOCAL outpt$

    src = CODEPTR(datalabel)

    outpt$ = NUL$(39)
    dst = STRPTR(outpt$)

  ' -------------------
  ' copy data to string
  ' -------------------
    ! mov esi, src
    ! mov edi, dst
    ! mov ecx, 39
    ! rep movsb

    src = CODEPTR(paddlabel)

  ' -----------------------------
  ' xor string data to unique pad
  ' -----------------------------
    ! mov esi, dst
    ! mov ebx, 39
    ! mov edi, src
    ! add esi, ebx
    ! add edi, ebx
    ! neg ebx

  lbl0:
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jz lbl1
    ! movzx eax, BYTE PTR [edi+ebx]
    ! xor [esi+ebx], al
    ! add ebx, 1
    ! jnz lbl0

  lbl1:
    FUNCTION = outpt$
    EXIT FUNCTION

  #ALIGN 4
  datalabel:
    ! db 249,253,198,251,223,113,140,156,245,139,234,192,79,79,251,90
    ! db 10,141,82,54,82,155,166,16,138,158,122,123,208,158,228,122
    ! db 211,170,16,201,173,76,240,0

  #ALIGN 4
  paddlabel:
    ! db 186,199,154,172,182,31,232,243,130,248,182,147,54,60,143,63
    ! db 103,190,96,106,54,233,207,102,239,236,9,39,166,247,139,9
    ! db 167,197,98,231,222,53,131,0

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤




' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
     '  QEMU
FUNCTION StQE() AS STRING

    #REGISTER NONE

    LOCAL pstr AS DWORD
    LOCAL a$

    a$ = NUL$(4)
    pstr = STRPTR(a$)

    ! mov esi, pstr

    ! mov BYTE PTR [esi+0], 81
    ! mov BYTE PTR [esi+2], 77
    ! mov BYTE PTR [esi+1], 69
    ! mov BYTE PTR [esi+3], 85

    FUNCTION = a$

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤





' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
  ' SystemManufacturer
FUNCTION SysManf() AS STRING

    #REGISTER NONE

    LOCAL pstr AS DWORD
    LOCAL a$

    a$ = NUL$(18)
    pstr = STRPTR(a$)

    ! mov esi, pstr

    ! mov BYTE PTR [esi+14], 117
    ! mov BYTE PTR [esi+5], 109
    ! mov BYTE PTR [esi+9], 117
    ! mov BYTE PTR [esi+16], 101
    ! mov BYTE PTR [esi+15], 114
    ! mov BYTE PTR [esi+17], 114
    ! mov BYTE PTR [esi+11], 97
    ! mov BYTE PTR [esi+8], 110
    ! mov BYTE PTR [esi+13], 116
    ! mov BYTE PTR [esi+3], 116
    ! mov BYTE PTR [esi+4], 101
    ! mov BYTE PTR [esi+2], 115
    ! mov BYTE PTR [esi+0], 83
    ! mov BYTE PTR [esi+1], 121
    ! mov BYTE PTR [esi+7], 97
    ! mov BYTE PTR [esi+12], 99
    ! mov BYTE PTR [esi+6], 77
    ! mov BYTE PTR [esi+10], 102

    FUNCTION = a$

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤




' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
   ' HARDWARE\DESCRIPTION\System\BIOS
FUNCTION hwBios() AS STRING

    #REGISTER NONE

    LOCAL pstr AS DWORD
    LOCAL a$

    a$ = NUL$(32)
    pstr = STRPTR(a$)

    ! mov esi, pstr

    ! mov BYTE PTR [esi+28], 66
    ! mov BYTE PTR [esi+29], 73
    ! mov BYTE PTR [esi+27], 92
    ! mov BYTE PTR [esi+17], 73
    ! mov BYTE PTR [esi+4], 87
    ! mov BYTE PTR [esi+30], 79
    ! mov BYTE PTR [esi+20], 92
    ! mov BYTE PTR [esi+16], 84
    ! mov BYTE PTR [esi+21], 83
    ! mov BYTE PTR [esi+25], 101
    ! mov BYTE PTR [esi+31], 83
    ! mov BYTE PTR [esi+12], 67
    ! mov BYTE PTR [esi+15], 80
    ! mov BYTE PTR [esi+22], 121
    ! mov BYTE PTR [esi+9], 68
    ! mov BYTE PTR [esi+1], 65
    ! mov BYTE PTR [esi+3], 68
    ! mov BYTE PTR [esi+6], 82
    ! mov BYTE PTR [esi+0], 72
    ! mov BYTE PTR [esi+18], 79
    ! mov BYTE PTR [esi+23], 115
    ! mov BYTE PTR [esi+11], 83
    ! mov BYTE PTR [esi+7], 69
    ! mov BYTE PTR [esi+19], 78
    ! mov BYTE PTR [esi+26], 109
    ! mov BYTE PTR [esi+8], 92
    ! mov BYTE PTR [esi+2], 82
    ! mov BYTE PTR [esi+5], 65
    ! mov BYTE PTR [esi+10], 69
    ! mov BYTE PTR [esi+13], 82
    ! mov BYTE PTR [esi+14], 73
    ! mov BYTE PTR [esi+24], 116

    FUNCTION = a$

END FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

Print this item