/* <rexxtags:xmlhighlight>: a quick and dirty REXX tag to highlight XML code  */
/*                                                                            */
/* Parameters:                                                                */ 
/*   lineno="[YES|1|NO|0]"       (Optional; default: NO)                      */
/*   file="[filename]"           (Optional; default: "")                      */
/*                                                                            */
/* Version:     1.1                                                           */
/*                                                                            */
/* Author:      (c) Jose Maria Blasco <jm@jmblasco.com>                       */
/*                                                                            */
/* This software is subject to the terms of the Common Public License. You    */
/* must accept the terms of this license to use this software. Refer to       */
/* the license at the following URL for more information:                     */
/* http://oss.software.ibm.com/developerworks/opensource/CPLv1.0.htm          */
/*                                                                            */
/* Description: A quick-and-dirty XML code highlighter which is used          */
/* in the REXXTAGS tutorial (and elsewhere on the REXXTAGS site,              */
/* http://www.rexxtags.org ). I wrote it in 30 minutes to test code           */
/* highlighting, and invested later some more time so that the code is        */
/* readable and has some documentation                                        */
/*                                                                            */
/* Disclaimer: I wrote this program for my own needs (mainly, for the         */
/* REXXTAGS tutorial). It is NOT a complete XML highlighter, nor does it      */
/* handle all syntactical cases. Use at your own risk.                        */
/*                                                                            */
/* Modifications:                                                             */
/*                                                                            */
/* Date       Author      Description                                         */
/* ---------- ----------- --------------------------------------------------- */
/* 2002/12/05 J.M.Blasco  v1.0 Initial release                                */
/* 2011/12/29 J.M.Blasco  v1.0 Q&D adapt to REXXHTTP                          */

Use arg request,response, output, verb, parms, body
                            /* Standard parse for tags which do body handling */

Call GetParms               /* We'll need the parameters in many of the calls */


/*----------------------------------------------------------------------------*/
/* The tag is TAGDEPENDENT or not _depending_ on whether we are specifying    */
/* a 'file' parameter.                                                        */
/*----------------------------------------------------------------------------*/

If verb == 'QUERY BODY CONTENT' Then
  If file == '' Then Return 'TAGDEPENDENT'
  Else Return 0

/*----------------------------------------------------------------------------*/
/* If a 'file' parameter is specified, the tag should not have a body, and    */
/* all processing occurs at the start tag; otherwise, we delay processing     */
/* until the body has been processed (that is, until the 'BODY' call).        */
/*----------------------------------------------------------------------------*/

If verb == 'START' Then 
  If file == '' Then Return ''
  Else Signal StartTag

If verb == 'BODY' Then Do   /* Standard body processing                       */
  Interpret body
  Signal Body
End
  
If verb == 'END' Then Return '' 

Return 0

/*----------------------------------------------------------------------------*/
/* This routine gets called only when a 'file' parameter has been specified   */
/* and this is the 'START' call. The routine reads the file into a 'body.'    */
/* stems, and then branches to normal body processing.                        */
/*----------------------------------------------------------------------------*/

StartTag:
  Call on notready name seteof
  eof = 0
  body.0 = 0
  file = Stream(file,'c','query exists')
  
  If file == '' Then Signal Body 
  l = LineIn(file)
  Do lineno = 1 By 1 While eof == 0
    body.lineno = l
    body.0 = lineno
    l = LineIn(file)
  End
  Signal Body

/*----------------------------------------------------------------------------*/
/* This is to set an end-of-file indicator for StartTag's main read loop.     */
/*----------------------------------------------------------------------------*/

SetEof:
  eof = 1
Return

/*----------------------------------------------------------------------------*/
/* Parse the XML parameters                                                   */
/*----------------------------------------------------------------------------*/

GetParms:

  Parse var parms 'lineno="'lineno'"'
  If Translate(lineno) == "YES" Then lineno = 1
  If lineno \= 1 Then lineno = 0
  printlinenos = lineno

  Parse var parms 'file="'file'"'

  If file <> '' Then file = 'c:/Dropbox/webs/rexxtags'file
  
Return 

/*----------------------------------------------------------------------------*/
/* Body processing routine. Does all the highlighting.                        */
/*----------------------------------------------------------------------------*/

Body:

  state = 0              /* State variable. 0: Normal text; 1: Inside XML tag */
  r = ''                 /* This will hold the accumulated result             */
  
  diff = 0               /* Allow for the first line to be blank, and in..    */
  lineno = 1             /* ..this case, ignore it.                           */
  if body.1 = '' then do
    lineno = 2
    diff = 1
  End

  /* Main loop                                                                */

  Do lineno = lineno to body.0
  
    l = body.lineno      /* If the last line is blank, ignore it              */
    If l = '' & lineno = body.0 Then Leave
    
    l = change(l,'&','&amp;')                /* Don't mess with '&'           */
    l = change(l,'  ','&nbsp; ')             /* Don't allow blank sequences.. */
    l = change(l,'  ','&nbsp; ')             /* to collapse.                  */
    
    l1 = ''              /* 'll' contains the already processed part of 'l'   */
    Do Forever
      If state = 0 & Pos('<',l) > 0 Then Do   /* State change: Normal --> XML */
        p = Pos('<',l)
        state = 1
	l1 = l1||Left(l,p-1)'<font color="#0000ff"><b>&lt;'
	l = Substr(l,p+1)
	End
      Else If state = 1 & Pos('>',l) > 0 Then Do   /* XML --> Normal text     */
        p = Pos('>',l)
        state = 0
	l1 = l1||Left(l,p-1)'&gt;</b></font>'
	l = Substr(l,p+1)
	End
      Else Leave /* Leave when no more '<' or '>' in line                     */
    End
    l = l1||l
    If printlinenos Then l = '<font color="#999999"><font size="1">'Change(Right(lineno-diff,3),' ','&nbsp;')'</font>:</font>'l
    If lineno = 1 Then r = '<br />'l
    Else r = r'00'x||'<br />'l
  End
Return '<font face="Courier New,Courier,Arial">'r'</font>'

/* The following internal function is from Mike Cowlishaw  */
/* (posted in comp.lang.rexx)                              */
/* Internal function:  CHANGE(string,old,new)              */
/*                                                         */
/* (Like XEDIT  "C/old/new/1 *")                           */
/*                                                         */
/* Changes all occurrences of "old" in "string" to "new".  */
/* If "old"=='', then "new" is prefixed to "string".   MFC */
Change: procedure expose changed
  parse arg string, old, new
  if old=='' then do; changed=1; return new||string; end
  out=''; changed=0
  do while pos(old,string)\=0
    parse var string prefix (old) string
    out=out||prefix||new
    changed=changed+1
    end
  return out||string
