/* : 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.0 */ /* */ /* Author: (c) Jose Maria Blasco */ /* */ /* 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 */ Parse arg 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'"' 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,'&','&') /* Don't mess with '&' */ l = change(l,' ','  ') /* Don't allow blank sequences.. */ l = change(l,' ','  ') /* 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)'<' 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)'>' l = Substr(l,p+1) End Else Leave /* Leave when no more '<' or '>' in line */ End l = l1||l If printlinenos Then l = ''Change(Right(lineno-diff,3),' ',' ')':'l If lineno = 1 Then r = '
'l Else r = r'00'x||'
'l End Return ''r'' /* 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