/***************************************************************************
 *  XCOUNT.CMD - a REXX script to send count users hitting the home-page
 *
 *  Author:  Patrick Erley, Wolfram Fassbender, FU-Berlin WRZ
 *           18.8.1995
 *
 *   Modified by: Donald L. Meyer,  28.9.1995
 *   Modified again, by: Donald L. Meyer,  4.10.1995
 *     (Reworked XBM output to use LF instead of CRLF,
 *       now compatible with Netscape, et.al.  )
 *
 **************************************************************************/
env = "OS2ENVIRONMENT"
minLen = 7;           /* minimum number of digits in bitmap */
isHigh = 1;           /* if 1, digits are 16 pixels high, to allow room for border */
isInverse = 1;        /* if 1, digits are white on black */
totalreads = 0;       /* number of total reads */
bytes = '';
bytecount = 0;
AccessFile = 'access.cnt'
Incr = 1		/* default is to auto-increment  */

PathTranslated = translate(value( 'PATH_TRANSLATED',, env), '\', '/')
if (right(PathTranslated,1) \= '\') then PathTranslated = PathTranslated'\'
if (PathTranslated \= '\') then value( 'COUNT_FILENAME', PathTranslated || AccessFile, env)

parse arg ArgTxt
ArgTxt = translate(ArgTxt, ' ', '+')	/* older server versions sometimes forget to do this... */
parse var ArgTxt URI I L CLIENTADDR .
if (I \= '') then isInverse = I
if (L \= '') then minLen = L
if (CLIENTADDR == '') then CLIENTADDR = value( REMOTE_ADDR,, env)

   /* bitmap for each digit
      Each digit is 8 pixels wide, 10 high
      invdigits.x are white on black, digits.x black on white */
   invdigits.0 = "c3 99 99 99 99 99 99 99 99 c3";   /* 0 */
   invdigits.1 = "cf c7 cf cf cf cf cf cf cf c7";   /* 1 */
   invdigits.2 = "c3 99 9f 9f cf e7 f3 f9 f9 81";   /* 2 */
   invdigits.3 = "c3 99 9f 9f c7 9f 9f 9f 99 c3";   /* 3 */
   invdigits.4 = "cf cf c7 c7 cb cb cd 81 cf 87";   /* 4 */
   invdigits.5 = "81 f9 f9 f9 c1 9f 9f 9f 99 c3";   /* 5 */
   invdigits.6 = "c7 f3 f9 f9 c1 99 99 99 99 c3";   /* 6 */
   invdigits.7 = "81 99 9f 9f cf cf e7 e7 f3 f3";   /* 7 */
   invdigits.8 = "c3 99 99 99 c3 99 99 99 99 c3";   /* 8 */
   invdigits.9 = "c3 99 99 99 99 83 9f 9f cf e3";   /* 9 */
   
   
      digits.0 = "3c 66 66 66 66 66 66 66 66 3c";   /* 0 */
      digits.1 = "30 38 30 30 30 30 30 30 30 30";   /* 1 */
      digits.2 = "3c 66 60 60 30 18 0c 06 06 7e";   /* 2 */
      digits.3 = "3c 66 60 60 38 60 60 60 66 3c";   /* 3 */
      digits.4 = "30 30 38 38 34 34 32 7e 30 78";   /* 4 */
      digits.5 = "7e 06 06 06 3e 60 60 60 66 3c";   /* 5 */
      digits.6 = "38 0c 06 06 3e 66 66 66 66 3c";   /* 6 */
      digits.7 = "7e 66 60 60 30 30 18 18 0c 0c";   /* 7 */
      digits.8 = "3c 66 66 66 3c 66 66 66 66 3c";   /* 8 */
      digits.9 = "3c 66 66 66 66 7c 60 60 30 1c";   /* 9 */

/* get counter from file and increment it */
totalreads = Count( URI, Incr, CLIENTADDR)

/* now generate the Bitmap
                    minLen contains minimum number of digits to display
                    isHigh is one for 16 bit high numbers (else 10)
                    isInverse is one for reverse video (white on black) */
/* Stuff 0 to length of counter */
len = Length(totalreads);
crlf = '0a'x		/* image/x-xbitmap format depends on only having a LF char... */
if len < minLen Then len = minlen;
  formattedcount = right(totalreads, len, '0');

if isHigh then do 
   do i = 0 to len * 3 - 1 
      if isInverse then
         bytes = bytes"0xff";       /* add three blank rows to each digit */
      else 
         bytes = bytes"0x00";
      bytecount = bytecount + 1;
      if bytecount//len <> 0
      then bytes=bytes','
      else bytes=bytes',' || crlf
   end
end         
      
/* make the digits */
do y = 0 to 9 
   do x = 1 to len
      digit = substr(formattedCount,x,1);
      if isInverse then               /* $inv = 1 for inverted text */
         byte = substr(invdigits.digit, y*3+1,2);
       else 
         byte = substr(digits.digit,y*3+1,2);
         bytes = bytes'0x'byte;
      bytecount = bytecount + 1;
      if bytecount//len <> 0
      then bytes=bytes','
      else bytes=bytes',' || crlf
   end    
end
if isHigh then do
   do i = 0 to len*3 - 1
      if isInverse then
         bytes = bytes"0xff";       /* add three blank rows to each digit */
      else 
         bytes = bytes"0x00";
      bytecount = bytecount + 1;
      if bytecount//len <> 0
      then bytes=bytes','
      else bytes=bytes',' || crlf
   end
end

Say "Content-type: image/x-xbitmap";
/*Say "Content-type: text/plain";*/
Say;
out_text = "#define count_width "len*8 || crlf
if isHigh then
   out_text = out_text || "#define count_height 16" || crlf
else
   out_text = out_text || "#define count_height 10" || crlf
out_text = out_text || "static char count_bits[] = {" || crlf
out_text = out_text || reverse(substr(reverse(bytes), (2 + length(crlf))))'};' || crlf
call lineout, out_text

Exit (0)


Count: procedure
/* COUNT.RXX   - a function to track access counts of a given URL. */
/*	Original work by V. Phaniraj,  phaniraj@plains.nodak.edu		*/
/*	Heavily modified by D.L. Meyer,   meyer@larch.ag.uiuc.edu	*/

  env = 'OS2ENVIRONMENT'
  crlf = '0d0a'x
  open_mode = 'OPEN'
  number = 1
  count. = ''

  count.fn = value( 'COUNT_FILENAME',, env)
  if (count.fn == '') then count.fn='access.cnt'  /* ASCII file that contains the counts */

  count.exclude_ips = value( 'COUNT_EXCLUDE_IPS',, env)

  parse arg URI, count.Incr, CLIENTADDR
  if (count.Incr == '') | (count.Incr == 0) 
    then count.Incr = 0
    else count.Incr = 1

  if (CLIENTADDR == '') then CLIENTADDR = '#'

  URL=translate( URI)

  if (pos(CLIENTADDR, count.exclude_ips) > 0) then count.Incl = 0
  if (count.Incl == 0) then open_mode = 'OPEN READ'

/* read the access file into result and close the file  */

  rc = ''
  result = ''
  rest = ''
  do until (rc == 'READY:')
    rc=stream(count.fn, 'C', 'OPEN')
  end
  result=charin(count.fn,,chars(count.fn))

/* look for the URL in the  string, and find the
   number of accesses stored in the file. Try not to
   use linein to avoid keeping the file open too long.
*/

  locate = pos(URL,result)

  if (locate \= 0) then do
     locate = locate+length(URL)+2
     number=substr(result,locate)
     parse var number 'Accesses:' number 'here' (crlf) rest

/* This is the IP exclusion part... */
     if (count.Incr) then do
  
/* increment the number of accesses */

        number=number+1

/*  This is the updating of the file, if URL is found */
        parse upper version rver .
        aad=' '
        if abbrev(rver,'OBJ')=1 then aad=' WRITE'
        rc=stream(count.fn, 'C', 'SEEK ='||(locate)||aad)
        rc=charout(count.fn, 'Accesses: ' number ' here'crlf || rest)
     end
  end

  else if (count.Incr) then do
/*  This is the updating of the file, if URL is not found 
    A new entry is created in the file */

     parse upper version rver .
     aad=' '
     if abbrev(rver,'OBJ')=1 then aad=' WRITE'
     rc=stream(count.fn, 'C', 'SEEK +0'||aad)
     rc=lineout(count.fn,URL)
     rc=charout(count.fn, 'Accesses:  1  here'crlf || rest)
  end /* end of locate if */

  rc=stream(count.fn, 'C', 'CLOSE')
  number = strip(number)

return number


