home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / EPMATR.ZIP / ATTR.E next >
Text File  |  1992-11-19  |  28KB  |  698 lines

  1. const
  2.    FIND_NEXT_ATTR_SUBOP = 1
  3.    FIND_PREV_ATTR_SUBOP = 2
  4.    FIND_MATCH_ATTR_SUBOP = 3
  5.    DELETE_ATTR_SUBOP = 16
  6.    ANY_CLASS  = 0
  7.    COLORCLASS = 1
  8.    HIDNCLASS  = 2
  9.    ASSOCCLASS = 3
  10.    BUTTONCLASS= 4
  11.    CALCSTACK_CLASS = 10
  12.  
  13. /*
  14.      ShowMessage is a handy procedure that has nothing to do with attribute
  15.   support. It simply displays (multi-line) messages in a simulated dialog box
  16.   without causing the editor to update the text on the screen. The message is
  17.   simply pumpped directly to the screen. The user must hit a key to
  18.   remove the message from the screen.
  19.      This can be very handy for debugging. When used with the MessageNWait()
  20.   function, this function can facilitate the debugging of E macro code. It
  21.   also provides a nice way to present messages to users.
  22.  
  23. */
  24. ; LAM - SAYAT is broken on 5.50 and above, so do this as a WinMessageBox.
  25.  
  26. defproc showmessage()
  27. compile if EVERSION >= '5.50'
  28.    msgtext = ''
  29.    do i=1 to arg()
  30.       msgtext = msgtext || strip(arg(i))' '
  31.    enddo
  32.    call winmessagebox("ShowMessage", msgtext, 16454)  -- CANCEL + ICONHAND + MOVEABLE
  33. compile else
  34.     compile if EVERSION < 5
  35.        display 0;
  36.     compile else
  37.        display -1;   -- disablethe refresh of text
  38.     compile endif
  39.     color = 57;
  40.     sayat   "┌──────────────────────────────────────────────────────────────┐",8,       2, color;
  41.     for i = 1 to ARG()
  42.        sayat "│ "                                                              ,8+i,     2, color;
  43.        sayat                  substr(ARG(i), 1, 60)                            ,8+i,     4, color+2;
  44.        sayat                                                               " │",8+i,    64, color;
  45.     endfor
  46.     sayat   "│                                                              │",9 +ARG(),2, color;
  47.     compile if EVERSION < 5
  48.        sayat   "│"                                                               ,10+ARG(),2, color;
  49.        sayat    "               Hit any key to continue...                     " ,10+ARG(),3, color+1;
  50.     compile else
  51.        sayat   "│"                                                               ,10+ARG(),2, color;
  52.        sayat    "                                                              " ,10+ARG(),3, color+1;
  53.     compile endif
  54.     sayat                                                                  "│",10+ARG(),65, color;
  55.     sayat   "└──────────────────────────────────────────────────────────────┘",11+ARG(),2, color;
  56.     .line=.line; .col=.col;  /* Sideeffect of this assignment insures */
  57.                              /* message disappears after getkey().    */
  58.     compile if EVERSION < 5
  59.        thekey = getkey();
  60.     compile else
  61.        Dumb = 1;
  62.        for i = 1 to 500;
  63.           Dumb = (Dumb * 31) // 113;
  64.        endfor
  65.     compile endif
  66.  
  67.     compile if EVERSION < 5
  68.        display 1;
  69.        return thekey;
  70.     compile else
  71.        display 1;     -- reenable the refresh of text
  72.     compile endif
  73. compile endif
  74.  
  75.  
  76.  
  77.  
  78.  
  79. /**********************************************************************
  80. What's it called : allocate_attr(model)
  81.  
  82. What's its parameters : char : a flag that indicates what attribute
  83.                                model is to be used for the attribute
  84.                                class being allocated. As of now, this field
  85.                                is unused, but in the future... registering the
  86.                                model of an attribute class will simplify
  87.                                some of our move/copy/delete problems. The
  88.                                attribute models that are supported are
  89.                                 '1' : tag model.
  90.                                 '2' : "set until next set" model
  91.                                 '3' : push/pop model.
  92.  
  93. What's it return: number : the attribute class granted to the caller.
  94.                                If no attribute class is available,
  95.                                the class returned will be 0.
  96.  
  97. What's it do: allocates a attribute class to the caller. This is useful
  98.               because it helps avoid situations where several utilities
  99.               are (accidently) using the same attribute for different
  100.               uses. Attribute class 0 is reserved as an error flag or
  101.               wild card indicator. Attribute classes in the range
  102.               1..63 are reserved for internal purposes within E. (We have
  103.               already used attribute class 1 to bind colors into text.)
  104.               That leaves 192 attribute classes for new uses within the
  105.               macro language.
  106. */
  107. defproc allocate_attr(model) =
  108.    universal allocated_attrclasses
  109.    universal allocated_attrmodels
  110.    i=pos(' ',allocated_attrclasses)
  111.    if i then
  112.       allocated_attrclasses = overlay('A', allocated_attrclasses, i)
  113.       i = i+63
  114.       allocated_attrmodels = overlay(model, allocated_attrmodels, i, 1)
  115.       return i
  116.    endif
  117.  
  118.  
  119. /**********************************************************************
  120. What's it called : deallocate_attr(class)
  121.  
  122. What's its parameters : number : a flag that indicates what attribute
  123.                                class is to be deallocated.
  124.  
  125. What's it return: nothing
  126.  
  127. What's it do: deallocates an attribute class number so that it can be resused
  128.               by other applications.
  129.  
  130.   warning : All occurances of the attribute records having this class should
  131.             be removed from all files in the editor. Failure to do this could
  132.             result in an old (unremoved) attribute record being interpretted
  133.             to have a new meaning if that attribute class is ever reallocated
  134.             to another application.
  135.               'deallocate_attr' does not delete all occurances of an attribute
  136.             class for you. It is the macro programmer's responsibility to do
  137.             this.
  138. */
  139. defproc deallocate_attr(TheClass) =
  140.  universal allocated_attrclasses
  141.  universal allocated_attrmodels
  142.  allocated_attrclasses = overlay(' ', allocated_attrclasses, TheClass-63)
  143.  
  144.  
  145. /*****************************************************************************
  146.    The next few procedures implement hidden text. See CBlock.e for an example
  147. of the use of these functions.
  148. */
  149.  
  150.  
  151. /***********************************************************************
  152. What's it called: next_pos_in_stream
  153.  
  154. What's its parameters: 1) OldPos : that expresses the old position
  155.                                    The format of that string is three
  156.                                    numbers: fileid, line, column. These
  157.                                    numbers are separated by a space.
  158.  
  159. What's it return:                  a string representing the next position
  160.                                    in a character stream. The string is in
  161.                                    the same format of as the input parameter.
  162.  
  163. What's it do:     For the most part, this function is obvious, but in
  164.                   the case of postions beyond the end of line it is not.
  165.                   If the input parameter specifies a character in the middle
  166.                   of a line, this function returns the position directly
  167.                   to the right of the former position. If the input parameter
  168.                   specifies the last character in a line, this function will
  169.                   return a pointer to the line terminator of that line. If the
  170.                   input parameter points beyond the last character of a line or
  171.                   at the line terminator character, it will next point to the
  172.                   first character of the next line. (If the next line only has
  173.                   a line terminator, then the first character of the next line
  174.                   is the line terminator.) If there are no more characters in
  175.                   the file, this function will return a value specifying line
  176.                   zero.
  177. */
  178. defproc next_pos_in_stream(OldPos) =
  179.    parse value OldPos with OldFile OldLine OldCol;
  180.    rc = 0
  181. compile if EVERSION > 5
  182.    display -2
  183. compile endif
  184.    OldLast = OldFile.last
  185. compile if EVERSION > 5
  186.    display 2
  187. compile endif
  188.    if rc then
  189.       sayerror 'Old fileid is invalid.'
  190.       stop
  191.    endif
  192.    if (OldLine>OldFile.last) then
  193.      return OldFile" 0 "OldCol
  194.    endif
  195.    getline TextOfLine, OldLine, OldFile
  196.    if (OldLine=OldFile.last) then
  197.       if OldCol>length(TextOfLine) then
  198.         return OldFile" 0 "OldCol
  199.       endif
  200.    endif
  201.    if OldCol>=length(TextOfLine) then
  202.       OldLine = OldLine + 1
  203.       NewCol  = OldCol>length(TextOfLine)
  204.    else
  205.       NewCol  = OldCol + 1
  206.    endif
  207.    return OldFile OldLine NewCol
  208.  
  209.  
  210.  
  211. /***********************************************************************
  212. What's it called: prev_pos_in_stream
  213.  
  214. What's its parameters: 1) OldPos : that expresses the old position
  215.                                    The format of that string is three
  216.                                    numbers: fileid, line, column. These
  217.                                    numbers are separated by a space.
  218.  
  219. What's it return:                  a string representing the next position
  220.                                    in a character stream. The string is in
  221.                                    the same format of as the input parameter.
  222.  
  223. What's it do:     For the most part, this function is obvious, but in
  224.                   the case of postions beyond the end of line it is not.
  225.                   If the input parameter specifies a character in the middle
  226.                   of a line, this function returns the position directly
  227.                   to the left of the former position. If the input parameter
  228.                   specifies the first character in a line, this function will
  229.                   return a pointer to the line terminator of the previous line.
  230.                   If the input parameter points beyond the last character of a
  231.                   line or at the line terminator character, this function will
  232.                   return a pointer to the last character on the line. (If there are
  233.                   no characters on the line, then it will return a pointer to
  234.                   the line terminator character of the previous line.)
  235.                   If there are no more characters in the file, this function
  236.                   will return a value specifying line zero.
  237. */
  238. defproc prev_pos_in_stream(OldPos) =
  239.    parse value OldPos with OldFile OldLine OldCol;
  240.    rc = 0
  241. compile if EVERSION > 5
  242.    display -2
  243. compile endif
  244.    OldLast = OldFile.last
  245. compile if EVERSION > 5
  246.    display 2
  247. compile endif
  248.    if rc then
  249.       sayerror 'Old fileid is invalid.'
  250.       stop
  251.    endif
  252.    -- I may need to add code here to check for an empty file.
  253.    if OldFile.last==0 then
  254.       return OldFile '0' OldCol
  255.    endif
  256.    if (OldLine>OldFile.last) then
  257.      return OldFile OldFile.last+1 '0'
  258.    endif
  259.    -- eliminate cases that result in values prior to top of file.
  260.    if not OldLine then
  261.      return OldFile 0 OldCol
  262.    endif
  263.    if OldLine<3 then
  264.      getline TextOfLine, 1, OldFile
  265.      if not length(TextOfLine) and ((OldLine=1) or not OldCol) then
  266.        return OldFile 0 OldCol
  267.      endif
  268.    endif
  269.    -- handle cases that change lines.
  270.    getline TextOfLine, OldLine, OldFile
  271.    if not (OldCol and length(TextOfLine)) then
  272.      getline TextOfLine, OldLine-1, OldFile
  273.      NewCol = length(TextOfLine)
  274.      NewLine = OldLine - 1
  275.    else
  276.      if OldCol>length(TextOfLine) then
  277.        NewCol = length(TextOfLine)
  278.      else
  279.        NewCol = OldCol - 1
  280.      endif
  281.      NewLine = OldLine
  282.    endif
  283.    return OldFile NewLine NewCol
  284.  
  285.  
  286. /***********************************************************************
  287. What's it called: highlight_phrase
  288.  
  289. What's its parameters: 1) string : the phrase to be highlighted
  290.                        2) number : the color of the highlighting
  291.  
  292. What's it do:     colors all occurances of a specified set of characters
  293.                   in a specified color. It does not attempt to
  294.                   uncolor the results of any previous calls to this
  295.                   procedure.
  296.  
  297. */
  298. defc highlight_phrase
  299.    parse arg Arg1 thecolor
  300.    if thecolor='' then
  301.      thecolor = 92
  302.    endif
  303.    getfileid ThisFileID
  304.    call psave_pos(OldCursorPos)
  305.    OldRC = RC
  306.    0
  307.    display -2
  308.    "l /"Arg1"/"
  309.    while not rc do
  310.      insert_attribute  COLORCLASS, 23,       0,  1, .col+length(Arg1)-1, .line
  311.      insert_attribute  COLORCLASS, thecolor, 1, -1, .col,                .line
  312.      repeat_find
  313.    endwhile
  314.    rc = OldRC
  315.    display 2
  316.    call prestore_pos(OldCursorPos)
  317.    if .levelofattributesupport = 0 then .levelofattributesupport = 1; endif
  318.  
  319. /***********************************************************************
  320. What's it called: highlight_identifier
  321.  
  322. What's its parameters: 1) string : the identifier to be highlighted
  323.                        2) number : the color of the highlighting
  324.  
  325. What's it do:     colors all occurances of a specified set of characters
  326.                   in a specified color. It does not attempt to
  327.                   uncolor the results of any previous calls to this
  328.                   procedure.
  329.  
  330.                   Uses grep search to recognize identifiers. Grep
  331.                   searching is relatively slow, so I also use normal
  332.                   search to speed up searching.
  333.  
  334. */
  335. defc highlight_identifier
  336.     parse arg TheIdentName thecolor .
  337.  
  338.     if (TheIdentName='') or (TheIdentName='.') then
  339.       if find_token(startcol, endcol) then
  340.          TheIdentName = substr(textline(.line), startcol, (endcol-startcol)+1)
  341.       else
  342.         call showmessage(" Cursor was not on a valid identifier.  Place   ",
  343.                          "  the cursor over a procedure name and ",
  344.                          "  try again.")
  345.         RC = 0
  346.         return
  347.       endif
  348.     endif
  349.     if thecolor=='' then
  350.       thecolor = 26
  351.     endif
  352.     getfileid ThisFileID
  353.     call psave_pos(OldCursorPos)
  354.     OldRC = RC
  355.     0
  356.     display -2; -- prevent "Not Found" error messages.
  357.     "l /"TheIdentName"/e" /* do exact search first to increase speed. Grep is slow */
  358.     if not RC then
  359.       if .col>1 then .col=.col-1; endif
  360.       "l /[^_a-zA-Z0-9]"TheIdentName"[^_a-zA-Z0-9]/g"
  361.     endif
  362.     while rc==0 do
  363.       insert_attribute COLORCLASS, 23,       0,  1, .col+length(TheIdentName), .line
  364.       insert_attribute COLORCLASS, thecolor, 1, -1, .col+1,                    .line
  365.       .col = .col+length(TheIdentName)+2
  366.       "l /"TheIdentName"/e" /* do exact search first to increase speed of grep search. */
  367.       if RC==0 then
  368.         if .col>1 then .col=.col-1
  369.         endif
  370.         "l /[^_a-zA-Z0-9]"TheIdentName"[^_a-zA-Z0-9]/g"
  371.       endif
  372.     endwhile
  373.     RC = OldRC
  374.     display 2   -- allow error messages again
  375.     call prestore_pos(OldCursorPos)
  376.    if .levelofattributesupport = 0 then .levelofattributesupport = 1; endif
  377.  
  378.  
  379. /***********************************************************************
  380. What's it called: find_insertion_points_for_region
  381.  
  382. What's its parameters: 1) number : The first line of the region
  383.                        2) number : The first col of the region
  384.                        3) number : The last line of the region
  385.                        4) number : The last col of the region
  386.                        5) number : The fileid of the file.
  387.                        5) var number : The offset of first position
  388.                        6) var number : The offset of second position
  389.  
  390. What's it do:     It finds the offsets where matching attribute records should
  391.                     be placed to encompass the specified region. The Line and
  392.                     Column numbers need not be returned because they
  393.                     have the same values as the input parameters.
  394.  
  395. crossref: see comment at the top of this file.
  396.  
  397. comment:  line marks are not handled very well.
  398.  
  399. */
  400. defproc find_insertion_points_for_region(fline, fcol, lline, lcol, fileid, var BeginOffset, var EndOffset)
  401.   -- Start at the top first.
  402.   TheLine = fline
  403.   TheCol  = fcol
  404.   TheOffset = -1
  405.   TheOffset2 = TheOffset
  406.   attribute_action FIND_MATCH_ATTR_SUBOP, TheClass, TheOffset2, TheCol, TheLine, fileid
  407.   while (TheClass<>0) and ((TheLine<lline) or ((TheLine==lline) and (TheCol<=lcol))) do
  408.     TheLine = fline
  409.     TheCol  = fcol
  410.     TheOffset = TheOffset-1
  411.     TheOffset2 = TheOffset
  412.     attribute_action FIND_MATCH_ATTR_SUBOP, TheClass, TheOffset2, TheCol, TheLine, fileid
  413.   endwhile
  414.   BeginOffset = TheOffset
  415.   TheLine = lline
  416.   TheCol  = lcol
  417.   TheOffset = 1
  418.   TheOffset2 = TheOffset
  419.   attribute_action FIND_MATCH_ATTR_SUBOP, TheClass, TheOffset2, TheCol, TheLine, fileid
  420.   while (TheClass<>0) and ((TheLine>fline) or ((TheLine==fline) and (TheCol>fcol)) or
  421.                            ((TheLine==fline)and(TheCol==fcol)and(TheOffset>BeginOffset))) do
  422.     TheLine = lline
  423.     TheCol  = lcol
  424.     TheOffset = TheOffset+1
  425.     TheOffset2 = TheOffset
  426.     attribute_action FIND_MATCH_ATTR_SUBOP, TheClass, TheOffset2, TheCol, TheLine, fileid
  427.   endwhile
  428.   EndOffset = TheOffset
  429.  
  430.  
  431. /***********************************************************************
  432. What's it called: bind_attr_to_region
  433.  
  434. What's its parameters: 1) number : The Class of the attribute records
  435.                                    that will encompass the marked area.
  436.                        2) number : The Value of the attribute records
  437.                                    that will encompass the marked area.
  438.                        3) number : The first line of the region
  439.                        4) number : The first col of the region
  440.                        5) number : The last line of the region
  441.                        6) number : The last col of the region
  442.                        7) number : The fileid of the region.
  443.  
  444. What's it do:     It puts push/pop style attributes around the marked
  445.                   region. If other attribute records are already
  446.                   at positions where it will place attribute records,
  447.                   it will insert the new records inside the existing
  448.                   attribute records.
  449.                   The attribute records will have a class and value
  450.                   specified on the command line.
  451.  
  452. crossref: see comment at the top of this file.
  453.  
  454. comment:  line marks are not handled very well.
  455.  
  456. */
  457. defc bind_attr_to_region
  458.   parse arg setclass setvalue fline fcol lline lcol fileid rest
  459.   -- Start at the top first.
  460.   call find_insertion_points_for_region(fline, fcol, lline, lcol, fileid,
  461.                                         BeginOffset, TheOffset)
  462.   insert_attribute setclass, setvalue, 1/*push*/, BeginOffset, fcol, fline, fileid
  463.   insert_attribute setclass, setvalue, 0/*pop*/,  TheOffset,   lcol, lline, fileid
  464.  
  465.  
  466. /***********************************************************************
  467. What's it called: bind_attr_to_marked_region
  468.  
  469. What's its parameters: 1) number : The Class of the attribute records
  470.                                    that will encompass the marked area.
  471.                        2) number : The Value of the attribute records
  472.                                    that will encompass the marked area.
  473.  
  474. What's it do:     It puts push/pop style attributes around the marked
  475.                   region. If other attribute records are already
  476.                   at positions where it will place attribute records,
  477.                   it will insert the new records inside the existing
  478.                   attribute records.
  479.                   The attribute records will have a class and value
  480.                   specified on the command line.
  481.  
  482. crossref: see comment at the top of this file.
  483.  
  484. comment:  line marks are not handled very well.
  485.  
  486. */
  487. defc bind_attr_to_marked_region
  488.    themarktype = marktype()
  489.    if themarktype=='' then   -- there is no mark
  490.       call messageNwait("Error, a mark must exist before it can be colored.")
  491.    else
  492.       getfileid thisfileid
  493.       getmark firstmline, lastmline,firstmcol,lastmcol,mkfileid
  494.       parse arg TheClass TheValue .
  495.       if mkfileid==thisfileid then
  496.          if themarktype=="CHAR" then
  497.             "bind_attr_to_region" TheClass TheValue firstmline firstmcol lastmline lastmcol mkfileid
  498.             --insert_attribute TheClass, TheValue, 1, -300, firstmcol, firstmline, mkfileid
  499.             --insert_attribute TheClass, 23,       0,  300, lastmcol,  lastmline,  mkfileid
  500.          elseif themarktype=="BLOCK" then
  501.             for i = firstmline to lastmline
  502.               "bind_attr_to_region" TheClass TheValue i firstmcol i lastmcol mkfileid
  503.               --insert_attribute TheClass, TheValue, 1, -300, firstmcol, i, mkfileid
  504.               --insert_attribute TheClass, 23,       0, 300, lastmcol,  i, mkfileid
  505.             endfor
  506.          elseif themarktype=="LINE" then
  507.             "bind_attr_to_region" TheClass TheValue firstmline 1 lastmline+1 0 mkfileid
  508.             --insert_attribute TheClass, TheValue, 1, -300,   1, firstmline, mkfileid
  509.             --insert_attribute TheClass, 23,       0,  300, 255, lastmline,  mkfileid
  510.          else
  511.             sayerror "Internal Error: weird mark type." themarktype
  512.          endif
  513.       else
  514.         call messageNwait("Error, marked region must be in current window before coloring.")
  515.       endif
  516.    endif
  517.  
  518.  
  519. /***********************************************************************
  520. What's it called: set_marked_region_to_color
  521.  
  522. What's its parameters: number : the color
  523.  
  524. What's it do:     it colors the marked region in the color specifed by
  525.                   the first parameter.
  526.  
  527. crossref: see comment at the top of this file.
  528.  
  529. comment:  line marks are not handled very well.
  530.  
  531. */
  532. defc set_marked_region_to_color
  533.    themarktype = marktype()
  534.    if themarktype=='' then  --there is no mark
  535.       call messageNwait("Error, a mark must exist before it can be colored.")
  536.    else
  537.       if  arg(1)=='' then
  538.          sayerror "Error: set_marked_region_to_color requires a color parameter"
  539.       else
  540.          "bind_attr_to_marked_region" 1 arg(1)    -- COLORCLASS key
  541.       endif
  542.    endif
  543.    if .levelofattributesupport = 0 then .levelofattributesupport = 1; endif
  544.  
  545. /****************************************************************************
  546.  What's it called: reveal_attrs_on_line
  547.  
  548.  What's its parameters: 1) number: linenumber of line to be revealed.
  549.  
  550.  What's it do:     appends a line to the current file that textually describes
  551.                    the contents of the specified line of the current file.
  552. */
  553. defc reveal_attrs_on_line
  554.   TheOffset = -300
  555.   TheColumn = 0
  556.   if arg(1) then
  557.     TheALine   = arg(1)
  558.   else
  559.     TheALine   = .line
  560.   endif
  561.   TheLine = TheALine
  562.   TheClass  = ANY_CLASS
  563.   TheOutString = ""  /* The line to be created. */
  564.   attribute_action FIND_NEXT_ATTR_SUBOP, TheClass, TheOffset, TheColumn, TheLine
  565.   while (TheClass) and (TheLine=TheALine)  do
  566.      query_attribute  TheClass, TheValue, IsPush, TheOffset, TheColumn, TheLine
  567.  
  568.      TheOutString = TheOutString"[c."TheColumn",of."TheOffset","
  569.  
  570.      if TheClass==COLORCLASS then
  571.        TheOutString = TheOutString"COLOR,v."TheValue
  572.      elseif TheClass==HIDNCLASS then
  573.        TheOutString = TheOutString"HIDN,v."TheValue
  574.      elseif TheClass==ASSOCCLASS then
  575.        TheOutString = TheOutString"ASSOC,v."TheValue
  576.      elseif TheClass==BUTTONCLASS then
  577.        TheOutString = TheOutString"BUTTN,v."TheValue
  578.      elseif TheClass==14 then
  579.        TheOutString = TheOutString"STYLE,v."TheValue
  580.      elseif TheClass==16 then
  581.        TheOutString = TheOutString"FONT,v."TheValue
  582.      else
  583.        TheOutString = TheOutString"Cls."TheClass",v."TheValue
  584.      endif
  585.  
  586.      if IsPush==1 then
  587.        TheOutString = TheOutString",PUSH"
  588.      elseif IsPush==0 then
  589.          TheOutString = TheOutString",POP"
  590.      elseif IsPush==2 then
  591.          TheOutString = TheOutString",TAG"
  592.      else
  593.          TheOutString = TheOutString",P"IsPush
  594.      endif
  595.  
  596.      TheOutString = TheOutString"]"
  597.      TheClass = ANY_CLASS
  598.      attribute_action FIND_NEXT_ATTR_SUBOP, TheClass, TheOffset, TheColumn, TheLine
  599.   endwhile
  600.   insertline TheOutString, .last+1
  601.  
  602.  
  603. -------------------------------------------------------------------------------
  604. defc test_attr_search
  605.   0; .col=1
  606.   TheOffset = -300
  607.   TheColumn = 1
  608.   TheLine   = 0
  609.   TheClass  = ANY_CLASS
  610.   attribute_action FIND_NEXT_ATTR_SUBOP, TheClass, TheOffset, TheColumn, TheLine
  611.   --TheOffset = signit(TheOffset)
  612.   while TheClass<>0 do
  613.     TheLine
  614.     .col  = TheColumn
  615.     query_attribute  TheClass, TheValue, IsPush, TheOffset, TheColumn, TheLine
  616.     call messageNwait("Found one. Class="TheClass" IsPush="IsPush" Offset="TheOffset" Value="TheValue" (L,C)=("TheLine","TheColumn")")
  617.     TheClass  = ANY_CLASS
  618.  
  619.     attribute_action FIND_NEXT_ATTR_SUBOP, TheClass, TheOffset, TheColumn, TheLine
  620.     --TheOffset = signit(TheOffset)
  621.   endwhile
  622.   .last+1
  623.   endline
  624.   call messageNwait("None found. Starting reverse search for attributes.")
  625.   TheOffset = 300
  626.   TheColumn = 255
  627.   TheLine   = .last+1
  628.   TheClass  = ANY_CLASS
  629.   attribute_action FIND_PREV_ATTR_SUBOP, TheClass, TheOffset, TheColumn, TheLine
  630.   --TheOffset = signit(TheOffset)
  631.   while TheClass<>0 do
  632.     TheLine
  633.     .col  = TheColumn
  634.     query_attribute  TheClass, TheValue, IsPush, TheOffset, TheColumn, TheLine
  635.     call messageNwait("Found one. Class="TheClass" IsPush="IsPush" Offset="TheOffset" Value="TheValue" (L,C)=("TheLine","TheColumn")")
  636.     TheClass  = ANY_CLASS
  637.     attribute_action FIND_PREV_ATTR_SUBOP, TheClass, TheOffset, TheColumn, TheLine
  638.     --TheOffset = signit(TheOffset)
  639.   endwhile
  640.   sayerror "No more found while searching backwards."
  641.  
  642.  
  643. defc enable_attr_keys
  644.      -- Button 1, Second Click, Alt
  645.      call register_mousehandler(1, '1 SECONDCLK 4', 'MH_executeclick')
  646.      -- Button 2, Second Click, Alt
  647.      call register_mousehandler(1, '2 SECONDCLK 4', 'blkexpansion_Expand_Blk')
  648.      -- Button 2, Second Click, Ctrl
  649.      call register_mousehandler(1, '2 SECONDCLK 2', 'blkexpansion_Compress_Blk')
  650.  
  651.  
  652.  
  653. defproc signit(TheNumString)
  654.  
  655.   if (length(TheNumString)<>10) then
  656.     return TheNumString
  657.   elseif ('y'TheNumString<='y2147483648') then
  658.     -- warning:
  659.     --          E converts the numbers to floating point numbers with
  660.     --          9 significant digits. To avoid this, a string compare
  661.     --          is done above.
  662.     --
  663.     /* We are positive so just return the given value */
  664.     return TheNumString
  665.   else
  666.     FourGig   = '4294967296'
  667.     HiDiff = substr(FourGig, 1, 5) - substr(TheNumString, 1, 5)
  668.     LoDiff = substr(FourGig, 6, 5) - substr(TheNumString, 6, 5)
  669.     if (HiDiff<0) or ((HiDiff=0) and (LoDiff<0)) then
  670.       -- TheNumString>FourGig
  671.       return TheNumString
  672.     endif
  673.     if LoDiff<0 then
  674.       LoDiff = '100000' + LoDiff
  675.       HiDiff = HiDiff - 1
  676.     endif
  677.     if not HiDiff then
  678.       HiDiff=''
  679.     endif
  680.     return '-'HiDiff||LoDiff
  681.   endif
  682.  
  683. definit
  684.   universal allocated_attrclasses
  685.   universal allocated_attrmodels
  686.   universal ATTR_installed
  687.   if ATTR_installed=="" then
  688.     ATTR_installed = "0"
  689.     allocated_attrclasses = substr(' ',1,192)
  690.     allocated_attrmodels  = substr('3',1,255)
  691.  
  692.           /* indicates color class uses push/pop model */
  693.     if filetype()='TST' then
  694.        keys attr_keys
  695.     endif
  696.   endif
  697.  
  698.