diff --git a/src/inc/cmdsys.plh b/src/inc/cmdsys.plh
index e8d6599..d48c91b 100644
--- a/src/inc/cmdsys.plh
+++ b/src/inc/cmdsys.plh
@@ -36,7 +36,7 @@ import cmdsys
     //
     // CMD exported functions
     //
-    predef putc(c)#0, putln()#0, puts(s)#0, getc()#1, gets(p)#1
+    predef putc(c)#0, putln()#0, puts(s)#0, puti(i)#0, getc()#1, gets(p)#1
     predef call(addr,areg,xreg,yreg,status)#1, syscall(cmd,params)#1
     predef heapmark()#1, heapallocalign(size, pow2, freeaddr), heapalloc(size)#1, heaprelease(newheap)#1, heapavail()#1
     predef memset(addr,value,size)#0, memcpy(dst,src,size)#0
diff --git a/src/inc/testlib.plh b/src/inc/testlib.plh
index f8a06ef..087b6f2 100644
--- a/src/inc/testlib.plh
+++ b/src/inc/testlib.plh
@@ -1,5 +1,4 @@
 import testlib
-  predef puti(i)#0
   word print
   const dec = 0
   const hex = 2
diff --git a/src/libsrc/dhcp.pla b/src/libsrc/dhcp.pla
index 529299c..6037e41 100644
--- a/src/libsrc/dhcp.pla
+++ b/src/libsrc/dhcp.pla
@@ -111,24 +111,12 @@ byte[] endDHCP
 //
 byte boundstr = "Apple II bound to:\n"
 byte dnsstr = "DNS: "
-def putln
-    return putc($0D)
-end
 def putb(hexb)
     return call($FDDA, hexb, 0, 0, 0)
 end
 def puth(hex)
     return call($F941, hex >> 8, hex, 0, 0)
 end
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
 def putip(ipptr)
     byte i
 
diff --git a/src/libsrc/inet.pla b/src/libsrc/inet.pla
index 35666f6..3930448 100644
--- a/src/libsrc/inet.pla
+++ b/src/libsrc/inet.pla
@@ -53,27 +53,15 @@ def iNetSetDNS(ipptr)
     return memcpy(@dns, ipptr, 4)
 end
 
-def putln
-    return putc($0D)
-end
 def putb(hexb)
     return call($FDDA, hexb, 0, 0, 0)
 end
 def puth(hex)
     return call($F941, hex >> 8, hex, 0, 0)
 end
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
 def putip(ipptr)
     byte i
-    
+
     for i = 0 to 2
         puti(ipptr->[i]); putc('.')
     next
@@ -81,7 +69,7 @@ def putip(ipptr)
 end
 def dumpbytes(buf, len)
     word i
-    
+
     for i = 0 to len - 1
         putb(buf->[i])
 	if i & 7 == 7
@@ -95,7 +83,7 @@ end
 def parseIP(ipstr, ipaddr)
     byte i
     word endstr
-    
+
     endstr = ipstr + ^ipstr
     for i = 0 to 3
 	ipstr = ipstr + 1
@@ -125,13 +113,13 @@ def parseDomain(domstr, msgptr)
     msgptr->[l] = i - l - 1
     msgptr  = msgptr + i
     ^msgptr = 0 // Terminate label list
-    return msgptr + 1 
+    return msgptr + 1
 end
 
 def recvDNS(remip, remport, pkt, len, ipaddr)
     byte q, r
     word resptr
-    
+
     if pkt=>dnsID == $BEEF
         q = pkt->dnsQdCount.1
         r = pkt->dnsAnCount.1 + pkt->dnsNsCount.1 + pkt->dnsArCount.1
@@ -174,7 +162,7 @@ end
 def iNetResolve(namestr, ipaddr)
     word dnspkt, msgptr, msglen
     word portDNS, timeout
-    
+
     ipaddr=>0 = 0
     ipaddr=>2 = 0
     if not parseIP(namestr, ipaddr)
diff --git a/src/libsrc/wiznet.pla b/src/libsrc/wiznet.pla
index 7260104..079ebf5 100644
--- a/src/libsrc/wiznet.pla
+++ b/src/libsrc/wiznet.pla
@@ -430,24 +430,12 @@ end
 //
 // DEBUG
 //
-def putln
-    return putc($0D)
-end
 def putb(hexb)
     return call($FDDA, hexb, 0, 0, 0)
 end
 def puth(hex)
     return call($F941, hex >> 8, hex, 0, 0)
 end
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
 def putip(ipptr)
     byte i
 
diff --git a/src/samplesrc/fatreaddsk.pla b/src/samplesrc/fatreaddsk.pla
index 089f213..b84886f 100644
--- a/src/samplesrc/fatreaddsk.pla
+++ b/src/samplesrc/fatreaddsk.pla
@@ -37,38 +37,6 @@ def putb(b)
     return putc(c)
 end
 
-def puti(i)
-    word tt, th, h, t
-    byte  p
-
-    p =0
-    if i < 0
-        putc('-')
-        i = -i
-    fin
-    tt = i / 10000
-    i  = i % 10000
-    th = i / 1000
-    i  = i % 1000
-    h  = i / 100
-    i  = i % 100
-    t  = i / 10
-    i  = i % 10
-    if tt > 0
-        putc(tt + '0'); p = 1
-    fin
-    if p or th > 0
-        putc(th + '0'); p = 1
-    fin
-    if p or h > 0
-        putc(h + '0'); p = 1
-    fin
-    if p or t > 0
-        putc(t + '0'); p = 1
-    fin
-    return putc(i + '0')
-end
-
 def charUpper(c)
     if c >= 'a' and c <= 'z'
         return c - LOWER_DIFF
@@ -78,7 +46,7 @@ end
 
 def getYN(prompt)
     byte yn
-    
+
     puts(prompt)
     yn = getc
     putln
@@ -87,7 +55,7 @@ end
 
 def trkSecToBlk(bufSec, bufBlk)
     byte sector
-    
+
     for sector = 0 to 15
         memcpy(bufBlk + (sector << 8), bufSec + (secOrder[sector] << 8), 256)
     next
@@ -95,7 +63,7 @@ end
 
 def bigFatWrite(buf, len)
     word xferLen, fatLen
-    
+
     xferLen = 0
     repeat
         if len > MAX_FAT_BUF_SIZE
@@ -118,7 +86,7 @@ end
 def fatReadImage(src, drv, order)
     word inBuf, outBuf, copyLen, freeAddr
     word blocknum, bufblk
-    
+
     inBuf = heapallocalign(COPY_BUF_SIZE * 2, 8, @freeAddr)
     if not inBuf
         puts("Not enough free memory!\n"); putln
@@ -170,7 +138,7 @@ arg = argNext(argFirst)
 if ^arg
     image = arg
     arg = argNext(arg)
-    if ^arg 
+    if ^arg
         when ^(arg + 1)
             is '2' // Drive 2 option
                 unit = DRIVE2
diff --git a/src/samplesrc/fatwritedsk.pla b/src/samplesrc/fatwritedsk.pla
index 2c786af..5fc8b60 100644
--- a/src/samplesrc/fatwritedsk.pla
+++ b/src/samplesrc/fatwritedsk.pla
@@ -38,38 +38,6 @@ def putb(b)
     return putc(c)
 end
 
-def puti(i)
-    word tt, th, h, t
-    byte  p
-
-    p =0
-    if i < 0
-        putc('-')
-        i = -i
-    fin
-    tt = i / 10000
-    i  = i % 10000
-    th = i / 1000
-    i  = i % 1000
-    h  = i / 100
-    i  = i % 100
-    t  = i / 10
-    i  = i % 10
-    if tt > 0
-        putc(tt + '0'); p = 1
-    fin
-    if p or th > 0
-        putc(th + '0'); p = 1
-    fin
-    if p or h > 0
-        putc(h + '0'); p = 1
-    fin
-    if p or t > 0
-        putc(t + '0'); p = 1
-    fin
-    return putc(i + '0')
-end
-
 def charUpper(c)
     if c >= 'a' and c <= 'z'
         return c - LOWER_DIFF
@@ -79,7 +47,7 @@ end
 
 def getYN(prompt)
     byte yn
-    
+
     puts(prompt)
     yn = getc
     putln
@@ -88,7 +56,7 @@ end
 
 def trkSecToBlk(bufSec, bufBlk)
     byte sector
-    
+
     for sector = 0 to 15
         memcpy(bufBlk + (sector << 8), bufSec + (secOrder[sector] << 8), 256)
     next
@@ -96,7 +64,7 @@ end
 
 def bigFatRead(buf, len)
     word xferLen, fatLen
-    
+
     xferLen = 0
     repeat
         if len > MAX_FAT_BUF_SIZE
@@ -119,7 +87,7 @@ end
 def fatWriteImage(src, drv, order)
     word inBuf, outBuf, copyLen, freeAddr
     word blocknum, bufblk
-    
+
     outBuf = heapallocalign(COPY_BUF_SIZE * 2, 8, @freeAddr)
     if not outBuf
         puts("Not enough free memory!\n"); putln
@@ -172,7 +140,7 @@ arg = argNext(argFirst)
 if ^arg
     image = arg
     arg = argNext(arg)
-    if ^arg 
+    if ^arg
         when ^(arg + 1)
             is '2' // Drive 2 option
                 unit = DRIVE2
@@ -206,4 +174,4 @@ else
     puts("Write DSK image to floppy disk drive\n")
     puts("Usage: +FATWRITEDSK <DSK image file> [1,2,T]\n")
 fin
-done
\ No newline at end of file
+done
diff --git a/src/samplesrc/httpd.pla b/src/samplesrc/httpd.pla
index edaa382..553d73f 100644
--- a/src/samplesrc/httpd.pla
+++ b/src/samplesrc/httpd.pla
@@ -129,24 +129,12 @@ end
 //
 // DEBUG
 //
-def putln
-    return putc($0D)
-end
 def putb(hexb)
     return call($FDDA, hexb, 0, 0, 0)
 end
 def puth(hex)
     return call($F941, hex >> 8, hex, 0, 0)
 end
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
 def putip(ipptr)
     byte i
 
diff --git a/src/samplesrc/memtest.pla b/src/samplesrc/memtest.pla
index 238a634..ec68a50 100644
--- a/src/samplesrc/memtest.pla
+++ b/src/samplesrc/memtest.pla
@@ -7,24 +7,12 @@ end
 word a, b, c, d, e, memptr
 word memfre, memlrgst
 
-def putln
-    return putc($0D)
-end
 def putb(hexb)
     return call($FDDA, hexb, 0, 0, 0)
 end
 def puth(hex)
     return call($F941, hex >> 8, hex, 0, 0)
 end
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
 
 sbrk($3000) // Set small pool size
 
diff --git a/src/samplesrc/rogue.io.pla b/src/samplesrc/rogue.io.pla
index 006c1d3..1764b0c 100644
--- a/src/samplesrc/rogue.io.pla
+++ b/src/samplesrc/rogue.io.pla
@@ -215,16 +215,6 @@ def a2gotoxy(x, y)
     return call($FB5B, y + ^$22, 0, 0, 0)
 end
 
-export def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
-
 export def toupper(c)
   if c >= 'a' and c <= 'z'
     c = c - $20
diff --git a/src/samplesrc/sanity.pla b/src/samplesrc/sanity.pla
index 9a3560d..4ec80ec 100644
--- a/src/samplesrc/sanity.pla
+++ b/src/samplesrc/sanity.pla
@@ -9,16 +9,6 @@ include "inc/sane.plh"
 word iA, iB, iC
 byte xT[t_extended]
 
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
-
 iA = 3
 iB = 4
 iC = -1
@@ -32,19 +22,19 @@ sane:zpRestore()
 puti(iA); putc('+'); puti(iB); putc('='); puti(iC); putc('\n')
 sane:zpSave()
 sane:fpOp2(FFINT|FOZ2X, @xT, @iA) // Convert int A to ext T
-sane:fpOp2(FFINT|FOSUB, @xT, @iB) // Add int B to ext T
+sane:fpOp2(FFINT|FOSUB, @xT, @iB) // Sub int B from ext T
 sane:fpOp2(FFINT|FOX2Z, @iC, @xT) // Convert ext T to int C
 sane:zpRestore()
 puti(iA); putc('-'); puti(iB); putc('='); puti(iC); putc('\n')
 sane:zpSave()
 sane:fpOp2(FFINT|FOZ2X, @xT, @iA) // Convert int A to ext T
-sane:fpOp2(FFINT|FOMUL, @xT, @iB) // Add int B to ext T
+sane:fpOp2(FFINT|FOMUL, @xT, @iB) // Mul int B by ext T
 sane:fpOp2(FFINT|FOX2Z, @iC, @xT) // Convert ext T to int C
 sane:zpRestore()
 puti(iA); putc('*'); puti(iB); putc('='); puti(iC); putc('\n')
 sane:zpSave()
 sane:fpOp2(FFINT|FOZ2X, @xT, @iA) // Convert int A to ext T
-sane:fpOp2(FFINT|FODIV, @xT, @iB) // Add int B to ext T
+sane:fpOp2(FFINT|FODIV, @xT, @iB) // Div int B into ext T
 sane:fpOp2(FFINT|FOX2Z, @iC, @xT) // Convert ext T to int C
 sane:zpRestore()
 puti(iA); putc('/'); puti(iB); putc('='); puti(iC); putc('\n')
diff --git a/src/samplesrc/sieve.pla b/src/samplesrc/sieve.pla
index 364563f..3498962 100644
--- a/src/samplesrc/sieve.pla
+++ b/src/samplesrc/sieve.pla
@@ -14,16 +14,6 @@ def beep
   return putc(7)
 end
 
-def puti(i)
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
-
 beep
 //for iter = 1 to 10
   memset(@flag, TRUE, sizepl)
diff --git a/src/samplesrc/test.pla b/src/samplesrc/test.pla
index be96122..580349f 100755
--- a/src/samplesrc/test.pla
+++ b/src/samplesrc/test.pla
@@ -93,7 +93,7 @@ export def main(range)#0
   puts("10 * 8 = "); puti(a * 8); putln
   puts("10 / 2 = "); puti(a / 2); putln
   puts(@hello)
-  when MACHID & $C8
+  when ^MACHID & $C8
     is $08
       puts(@a1)
       break
diff --git a/src/samplesrc/testlib.pla b/src/samplesrc/testlib.pla
index 2a50e73..a40749c 100755
--- a/src/samplesrc/testlib.pla
+++ b/src/samplesrc/testlib.pla
@@ -5,7 +5,7 @@ include "inc/cmdsys.plh"
 //
 // Module data.
 //
-predef puti(i)#0, puth(h)#0
+predef puth(h)#0
 export word print[] = @puti, @puth, @putln, @puts, @putc
 byte valstr[] = '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
 byte loadstr[] = "testlib loaded!"
@@ -19,15 +19,6 @@ def puth(h)#0
   putc(valstr[(h >> 4)  & $0F])
   putc(valstr[ h        & $0F])
 end
-export def puti(i)#0
-  if i < 0; putc('-'); i = -i; fin
-  if i < 10
-    putc(i + '0')
-  else
-    puti(i / 10)
-    putc(i % 10 + '0')
-  fin
-end
 puts(@loadstr)
 putln
 done
diff --git a/src/vmsrc/a1cmd.pla b/src/vmsrc/a1cmd.pla
index b972255..ec21df9 100755
--- a/src/vmsrc/a1cmd.pla
+++ b/src/vmsrc/a1cmd.pla
@@ -31,7 +31,7 @@ const CFFAEntryPtr = $0B
 // Pedefined functions.
 //
 predef syscall(cmd)#1, call(addr,areg,xreg,yreg,status)#1
-predef crout()#0, cout(c)#0, prstr(s)#0, cin()#1, rdstr(p)#1
+predef crout()#0, cout(c)#0, prstr(s)#0, print(i)#0, cin()#1, rdstr(p)#1
 predef markheap()#1, allocheap(size)#1, allocalignheap(size, pow2, freeaddr), releaseheap(newheap)#1, availheap()#1
 predef memset(addr,value,size)#0, memcpy(dst,src,size)#0
 predef uword_isgt(a,b)#1, uword_isge(a,b)#1, uword_islt(a,b)#1, uword_isle(a,b)#1
@@ -71,6 +71,7 @@ byte machidstr[]  = "MACHID"
 byte putcstr[]    = "PUTC"
 byte putlnstr[]   = "PUTLN"
 byte putsstr[]    = "PUTS"
+byte putistr[]    = "PUTI"
 byte getcstr[]    = "GETC"
 byte getsstr[]    = "GETS"
 byte sysstr[]     = "SYSCALL"
@@ -95,6 +96,7 @@ word              = @callstr,   @call
 word              = @putcstr,   @cout
 word              = @putlnstr,  @crout
 word              = @putsstr,   @prstr
+word              = @putistr,   @print
 word              = @getcstr,   @cin
 word              = @getsstr,   @rdstr
 word              = @hpmarkstr, @markheap
@@ -579,6 +581,11 @@ def prstr(str)#0
     i = i + 1
     loop
 end
+def print(i)#0
+    if i < 0; cout('-'); i = -i; fin
+    if i >= 10; print(i / 10); fin
+    cout(i % 10 + '0')
+end
 def rdstr(prompt)#1
     byte ch, maxlen
     maxlen = 0
diff --git a/src/vmsrc/cmd.pla b/src/vmsrc/cmd.pla
index 9b08b7d..b8f1995 100755
--- a/src/vmsrc/cmd.pla
+++ b/src/vmsrc/cmd.pla
@@ -25,7 +25,7 @@ const modinitkeep = $4000
 // Pedefined functions.
 //
 predef syscall(cmd,params)#1, call(addr,areg,xreg,yreg,status)#1
-predef crout()#0, cout(c)#0, prstr(s)#0, cin()#1, rdstr(p)#1
+predef crout()#0, cout(c)#0, prstr(s)#0, print(i)#0, cin()#1, rdstr(p)#1
 predef markheap()#1, allocheap(size)#1, allocalignheap(size, pow2, freeaddr)#1, releaseheap(newheap)#1, availheap()#1
 predef memset(addr,value,size)#0, memcpy(dst,src,size)#0
 predef uword_isgt(a,b)#1, uword_isge(a,b)#1, uword_islt(a,b)#1, uword_isle(a,b)#1
@@ -50,6 +50,7 @@ byte callstr    = "CALL"
 byte putcstr    = "PUTC"
 byte putlnstr   = "PUTLN"
 byte putsstr    = "PUTS"
+byte putistr    = "PUTI"
 byte getcstr    = "GETC"
 byte getsstr    = "GETS"
 byte hpmarkstr  = "HEAPMARK"
@@ -74,6 +75,7 @@ word            = @callstr,   @call
 word            = @putcstr,   @cout
 word            = @putlnstr,  @crout
 word            = @putsstr,   @prstr
+word            = @putistr,   @print
 word            = @getcstr,   @cin
 word            = @getsstr,   @rdstr
 word            = @hpmarkstr, @markheap
@@ -691,6 +693,14 @@ asm lookuptbl(dci, tbl)#1
         BNE     ---
 end
 //
+// Cheap and dirty print integer
+//
+def print(i)#0
+    if i < 0; cout('-'); i = -i; fin
+    if i >= 10; print(i / 10); fin
+    cout(i % 10 + '0')
+end
+//
 // ProDOS routines
 //
 def getpfx(path)#1
diff --git a/src/vmsrc/plvm.c b/src/vmsrc/plvm.c
index 642e33f..402c8bd 100755
--- a/src/vmsrc/plvm.c
+++ b/src/vmsrc/plvm.c
@@ -493,6 +493,13 @@ void call(uword pc)
             putchar('\n');
             fflush(stdout);
             break;
+        case 9: // LIBRARY STDLIB::MACHID
+            PUSH(0x0000);
+            break;
+        case 10: // LIBRARY STDLIB::PUTI
+            i = POP;
+            printf("%d", i);
+            break;
         default:
             printf("\nBad call code:$%02X\n", mem_data[pc - 1]);
             exit(1);
@@ -878,6 +885,7 @@ char *syslib_exp[] = {
     "GETS",
     "PUTLN",
     "MACHID",
+    "PUTI",
     0
 };
 
diff --git a/src/vmsrc/soscmd.pla b/src/vmsrc/soscmd.pla
index 2bcdfa7..79fb66c 100755
--- a/src/vmsrc/soscmd.pla
+++ b/src/vmsrc/soscmd.pla
@@ -26,7 +26,7 @@ const O_READ_WRITE = 3
 // Pedefined functions.
 //
 predef syscall(cmd,params)#1, call(addr,areg,xreg,yreg,status)#1
-predef crout()#0, cout(c)#0, prstr(s)#0, cin()#1, rdstr(p)#1
+predef crout()#0, cout(c)#0, prstr(s)#0, print(i)#0, cin()#1, rdstr(p)#1
 predef markheap()#1, allocheap(size)#1, allocalignheap(size, pow2, freeaddr), releaseheap(newheap)#1, availheap()#1
 predef memset(addr,value,size)#0, memcpy(dst,src,size)#0
 predef uword_isgt(a,b)#1, uword_isge(a,b)#1, uword_islt(a,b)#1, uword_isle(a,b)#1
@@ -68,6 +68,7 @@ byte callstr[]    = "CALL"
 byte putcstr[]    = "PUTC"
 byte putlnstr[]   = "PUTLN"
 byte putsstr[]    = "PUTS"
+byte putistr[]    = "PUTI"
 byte getcstr[]    = "GETC"
 byte getsstr[]    = "GETS"
 byte hpmarkstr[]  = "HEAPMARK"
@@ -91,6 +92,7 @@ word              = @callstr,   @call
 word              = @putcstr,   @cout
 word              = @putlnstr,  @crout
 word              = @putsstr,   @prstr
+word              = @putistr,   @print
 word              = @getcstr,   @cin
 word              = @getsstr,   @rdstr
 word              = @hpmarkstr, @markheap
@@ -806,6 +808,11 @@ def prstr(str)#0
         cout($0A)
     fin
 end
+def print(i)#0
+    if i < 0; cout('-'); i = -i; fin
+    if i >= 10; print(i / 10); fin
+    cout(i % 10 + '0')
+end
 def rdstr(prompt)#1
     cout(prompt)
     ^heap = read(refcons, heap + 1, 128)