_Examining the TAWK Compiler_ 
by James K. Lawless
Example 1:

(a)
finger jimbo@radiks.net

(b)
Connecting to host : radiks.net (205.138.126.6).
[radiks.net]
Login       Name               TTY         Idle    When    Where
jimbo    Jim Lawless           pts/6        <Nov 17 15:52> dial108.radiks.n


Listing One
# Jim Lawless -- jimbo@radiks.net
# FINGER.AWK -- This program implements a simple finger client.
# Syntax: finger id     ( finger jimbo@radiks.net )
# or finger -l id  ( finger -l jimbo@radiks.net )
# To compile: awkcw -eo -xe -z finger.awk socket.awk

BEGIN {
   if( ARGC < 2 )
      syntax();
# Construct one long string out of the command-line parameters.
# Find the parameter with an "@" symbol and extract the hostname from it.
   for(i=1;i<ARGC;i++) {
      n=index(ARGV[i],"@");
      if(n) {
         hostname=substr(ARGV[i],n+1,
            length(ARGV[i])-n);
      }
      if( length(q) )
         q = q " " ARGV[i];
      else
         q = ARGV[i];
   if( hostname == "" )
      syntax();
# Create a socket.
   sock=_socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
# Connect the socket to our host.
   host=gethostaddr(hostname);
   print "Connecting to host : " \
      hostname " (" host ")." ;
   sock_addr=pack("@<s @>s @<l @x @x @x @x @x @x @x @x",
      PF_INET,79,inet_addr(host));
   flag=_connect( sock,sock_addr,length(sock_addr));
# If the connection has been established, send the string q to the host.
   if( flag==0) {
      b=strdup("\0",128);
      q=q "\r\n";
      _send(sock,q,length(q),0);
# Now, wait for a reply...no more than 15 seconds.
     i=0;
     retry_count=0;
     while(!i) {
        i=_recv(sock,b,128,0);
        if(!i) {
           retry_count++;
           sleep(1);
           if(retry_count>15) {
              break;
           }
        }
     }
     while(1) {
# Make sure we didn't time out on the last operation!
        if( retry_count>15) {
           break;
        }
# Print the returned data block.
        if(i!=0) {
           for(j=1;j<=i;j++) {
              printf("%c",substr(b,j,1));
           }
# Get more data.
           i=_recv(sock,b,128,0);
        }
# If we're out of data, stop.
        else {
           break;
        }
     }
# disable sends and receives.
     _shutdown(sock,2);
     _closesocket(sock);
  }
}
# Get a long integer from a given address in memory.
function peekl(addr)
{
   local p=0;
   local i;
   for(i=0;i<4;i++) {
      p*=256;
      p+=peek(addr+3-i);
   }
   return(p);
}
# Get the host address, given a host name (this returns a string).
function gethostaddr(hostname)
{
   local ret;
   local p;
   local i;
   local s;
   local realname;
  
   ret = _gethostbyname(hostname)
   if (ret == 0)  {
      return("");
   }
# get the host address here!
   p=peekl(ret+12);
   p=peekl(p);

   s="";
   s=peek(p) "." peek(p+1) "." peek(p+2) "." peek(p+3);
   return(s);
}
# Get a null-terminated string from an address in memory.
function getstring(addr)
{
   local ar
   unpack("@a",addr,ar)
   return ar[1]
}
function syntax()
{
   print "\n" \
   "Syntax:\n" \
   "   finger id     ( finger jimbo@radiks.net )\n" \
   "or\n" \
   "   finger -l id  ( finger -l jimbo@radiks.net )\n";
   exit();
}

Listing Two
# Jim Lawless -- jimbo@radiks.net
# ASORT.AWK -- This program will utilize TAWK's associative-array
# capabilities implemented as a simple file-sorting program
# Syntax: asort infile [ options ] 
# Options: /i or /I, Ignore case-sensitivity; /d or /D, Descending sequence
# To compile: awkcw -eoe -xe -z asort.awk

BEGIN {
   if( ARGC < 2 ) {
      print "Syntax:\n" \
            "   asort infile [ options ] \n\n" \
            "Options:\n" \
            "   /i or /I   Ignore case-sensitivity\n" \
            "   /d or /D   Descending sequence\n" ;
      exit();
   }
# Set SORTTYPE to default ASCII / Ascending
   SORTTYPE=2;
# Check command-line and alter SORTTYPE as necessary
   for(i=1;i<ARGC;i++) {
      if( ARGV[i]=="/i" || ARGV[i]=="/I") {
         SORTTYPE+=4;
      }
      if( ARGV[i]=="/d" || ARGV[i]=="/D") {
         SORTTYPE+=8;
      }
   }
}
# Main input rule. Increment a table entry using whole line as a key. Counter
# built in ar array indicates how many occurrences of specified line exist.
{ ar[$0]++ }

# Now, we're done with input. Get values out of the array and display them.
END {
   for(i in ar) {
      j=ar[i];
      while(j--) {
         print(i);
      }
   }
}


Listing Three
# Jim Lawless -- jimbo@radiks.net
# TIMER.AWK -- This program implements a Windows TimerProc callback function.
# Declare externals.  

extern winapi int SetTimer(int hwnd,int id,int milli, void *);
extern winapi int KillTimer(int);
extern winapi int name "PeekMessageA" PeekMessage(void *,int,int,int,int);
extern winapi int TranslateMessage(void *);
extern winapi int name "DispatchMessageA" DispatchMessage(void *);
# Use a global variable to control the timer.
global counter;

BEGIN {
   counter=0;
# Register the callback.
   proc=registercallback("timerproc");
# Create a timer that will activate ever 1000 milliseconds ( once per second )
   timer_id=SetTimer(0,0,1000,proc);
   PM_REMOVE=1;
# Create a buffer to hold the 28-byte MSG structure msg=strdup("\0",28);
   for(;;) {
# let Windows breathe!
      if( PeekMessage(msg,0,0,0,PM_REMOVE)) {
         TranslateMessage(msg);
         DispatchMessage(msg);
      }            
# See if we've iterated 10 times.
      if( counter >= 10 )
         break;
   }
# Stop the timer
   KillTimer(timer_id);
# Free up the callback
   unregistercallback("timerproc");
}
# This function will be invoked by Windows
function timerproc( hwnd, message, wparam, lparam)
{
   counter++;
   print "In timerproc...iteration number " counter;
}

5



