/* Process lines from the file, building datastream */ /* John Hartmann 4 Jul 1987 11:49:46 */ /*%test: sub qdi */ /*********************************************************************/ /* QDI.REXX (c) Copyright IBM Danmark ApS 1987, 2010. Property of */ /* IBM. An unchanged copy may be distributed freely. */ /* */ /* Refer to QDI.XEDIT for usage instructions. */ /* */ /* Change activity: */ /*11 Dec 2010 ... C++ stuff was severely broken. */ /*12 Feb 2010 +++ Add C++ style comments for C. */ /* 6 Mar 2003 +++ Improve performance. */ /*21 Nov 1997 +++ Redo FSM; don't nest strings. */ /*19 Nov 1997 +++ Cleanup; better state information. */ /*30 Apr 1996 +++ Add C comment and parens. */ /*********************************************************************/ signal on novalue parse arg, cols, /* testing */ /* Columns on display */ lines, /* Rows on display */ colours, /* Colour scheme; see the XEDIT macro */ hilite, /* Extended hiliting to use */ ps, /* Programmable symbol set to use */ filetype, /* The file type (REXX, C, H, etc.) */ cline, /* Line number of first line */ blanklines, /* Number of blank lines at top of screen */ startcolumn, /* Where to start */ . 'callpipe var STATE.'cline '1|var startstate' parse var startstate state cmtnest parennest address command 'GLOBALV SELECT QDI GET REXXPAREN REXXCONT' /* Discard blanks and test too */ rexxparen=rexxparen='1' rexxcont=rexxcont='1' firstcomment=length(colours)-1 /* First colour for comments */ /* Define the FSM to use */ select when filetype='PATTERN' then call do_pattern when find('C CPP C++ H HPP H++', filetype)>0 then call do_c otherwise call do_rexx end hiwater=cols If blanklines=0 Then clear='' Else clear='284100 2842F4 3c'x || d2c(blanklines*cols, 2) || '00'x data='c0c2'x ||, /* Clear and restore */ '11'x || d2c(lines*cols-1,2) ||, /* Go to last position */ '13'x ||, /* Insert cursor */ '1d 60'x ||, /* Make a protected field. */ clear ||, /* Possibly some blank lines */ '2841'x || hilite ||, /* Set hilite */ '2843'x || ps /* And program symbols */ signal on error noctl=xrange('01'x, '3f'x) || 'ff'x /*%PAGE*/ /*********************************************************************/ /* Finite state machine to scan a line */ /* */ /* Inputs are classified and the finite state machine navigated. */ /*********************************************************************/ colour=c.state col=-1 /* Force colour at beginning of line */ do lineno=1+blanklines hiwater=cols-(lineno=lines) 'readto line' 'callpipe (name QDI.REXX:86)', '|literal' state cmtnest max(0, parennest), '|var STATE.'cline '1' cline=cline+1 position=0 /* At the beginning of the line */ encoded=translate(line, encode2, encode1, '1') origline=line linecolours='' startcolour=colour do while line\='' /* Take parts of the line */ prevstate=state /* Save state before */ /* Any attempt to skip "uninteresting" characters will defy */ /* the two-character sequence tests. But it is safe in state */ /* 0, and we need some speed. */ ?=0 If state=0 Then Do /* Take a run of blank and "other" */ ?=verify(encoded, '01')-1 If ?=-1 Then ?=length(encoded) /* That's the lot */ End If ?>0 /* Other indeed */ Then Do parse var line c +(?) line encoded=substr(encoded, ?+1) a=0 /* Remain in state and do nothing */ End Else /* Character to further test */ Do parse var line c+1 line parse var encoded i+1 encoded i=max(i, 1) /* Treat blank as other */ a=substr(a.state, i, 1) state=substr(s.state, i, 1) End newcolour=colour If a\=0 Then interpret 'call ACTION_'a linecolours=linecolours || copies(colour, length(c)) colour=newcolour; end state=right(s.state, 1) If state=0 Then colour=c.0 /* Otherwise don't take state's colour */ /* Now generate the data stream for the selected columns */ linecolours=substr(linecolours, startcolumn+1, hiwater-(lineno=lines), colour) origline=substr(origline, startcolumn+1) do while length(linecolours)>0 lc=left(linecolours, 1) If col\=lc Then Do data=data || colour(lc) col=lc End run=verify(linecolours, lc)-1 /* Returns 1-origin */ If run=-1 /* All of it? */ Then run=length(linecolours) linecolours=substr(linecolours, run+1) parse var origline d +(run) origline d=translate(d, , noctl, '"') /* Be sure not to interfere */ ld=length(d) Select When length(linecolours)>0 | ld=run/* Not last part of line */ Then nop when run<10 /* Not worth the bother */ Then d=left(d, run) /* Be sure to append blanks */ When (d='') /* Even if length isn't zero */ Then d='3c'x || d2c(lineno*cols-(lineno=lines), 2) || '00'x when ld0 Then call cmtcolour 1 /* Switch after */ When cmtnest<0 Then say 'negative' data '***' line otherwise state=0 newcolour=c.state End return /*********************************************************************/ /* c++ style line comment //--- */ /*********************************************************************/ action_8: call nestcomment /* Start the comment */ cmtnest=0 /* End it now */ c=left(c || line, cols-position) line='' /* Nothing left */ encoded='' return /*********************************************************************/ /* Two asterisks in a comment. Probably a lot of them. Get there */ /* faster. */ /*********************************************************************/ action_9: ?=verify(encoded, '5') If ?=1 Then return call chewdata ? return cmtcolour: ??=firstcomment+cmtnest//2 If arg(1)='' /* After paren */ Then return ?? newcolour=?? If arg(1)='0' Then colour=newcolour return colour: return '2842'x || substr(colours, arg(1), 1) /*********************************************************************/ /* This part is test cases */ /*********************************************************************/ /* */ abc, /* a /* nested */ comment */ , /* but */ 0 abc, /* a /* nested */ comment */ /* and nothing */ a='abc"def"ghi"j*/kl' a="abc'd/*ef'ghi'j/*kl""xyz'def" a='abc''def' c="x\'y" /* here is an order  */ /* nested /* comment /* even more */ here */ 'ends" */ /* a long comment */ a line /* a long comment */ /* /* */ */ "a" /**/ /**/ "a" /**/ /***/ /***********/ /***/ "a" /** **/ "a" /* a long comment */ abc /* a long comment */ "abc" /* an even longer comment abcdefghin567y8u9yurty6tyutyut56 */ "abc" /* an even longer comment abcdefghin567y8u9yurty6tyutyut56 */ abc /* an even longer comment abcdefghin567y8u9yurty6tyutyut56 */ 'abc', /* cmt */ 'def' 'abc', /* cmt /**/ */ 'def' 'abc' 'defghij' 'xx' /'abc' / 'abc' */ 'abc' */ /**/ 'abc' /* // */ //* */ / /**/ abc 'abc' 'abcd' 'abcde' / * abc