home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / PCTAG.ZIP / RETROMAC.COM / RETRO.KML < prev    next >
Text File  |  1989-10-01  |  37KB  |  990 lines

  1. *
  2. * ----------------------------------------------
  3. * PC-TAGS(tm) RETRO Program for the KEDIT Editor
  4. * ----------------------------------------------
  5. *
  6. * KEDIT Macros to Search a PC-TAGS-Generated Tagfile and Retrieve a
  7. * Function Definition
  8. *
  9. * Copyright (C) 1989 by Moderne Software.  All rights reserved.
  10. * Moderne Software, P.O. Box 3638, Santa Clara, CA 95055-3638
  11. *
  12. * Limited permission is given to registered PC-TAGS users to modify this
  13. * file for their own personal use only.  This file may not be used for any
  14. * purpose other than in conjunction with the PC-TAGS software package.
  15. *
  16. * Entry Points
  17. * ------------
  18. *       pctags_auto      -- uses word under cursor for search
  19. *       pctags_prompt    -- prompts for a word to use in search
  20. *
  21. * Support Macros
  22. * --------------
  23. *       _init            -- initialize global variables
  24. *       _delimiter       -- determine if a character is a word delimiter
  25. *       _convert_slashes -- convert all slash characters in string to backslashes
  26. *       _dos_shell       -- execute RETROEXEC environment value thru DOS
  27. *       _find_first      -- get first matching file spec
  28. *       _find_next       -- get next matching file spec
  29. *       _get_tagfile     -- retrieve the name of the next tagfile to search
  30. *       _parse_file_spec -- break multiple tagfile specs into single parts
  31. *       _file_loaded     -- determine if a file is already loaded
  32. *       _save_dir_file   -- temporarily rename any existing DIR.DIR file
  33. *       _restore_dir     -- restore renamed directory file back to DIR.DIR
  34. *       _init_file       -- initialize editor settings for loaded file
  35. *       _pctags_main     -- search and retrieval workhorse code
  36. *
  37. * History
  38. * -------
  39. *  1 Oct 89 -- Version 1.00
  40. *
  41.  
  42. ****************************************
  43. :_init
  44.  
  45. * Macro : _init
  46. * Syntax: 'macro _init'
  47. * Entry : None.
  48. * Exit  : Global variables used by the RETRO operation are initialized.
  49. * Note  : This macro must be called every time pctags_auto or pctags_prompt
  50. *           are invoked.
  51.  
  52.         * You can change the pctags_tagname_case variable's value from
  53.         * CASE_SENSITIVE to CASE_INSENSITIVE if you want the search for
  54.         * a matching tagname to ignore case
  55.         'editv set pctags_tagname_case CASE_SENSITIVE'
  56.  
  57.         * The following variable values should not be changed
  58.         'editv set pctags_first_call 1'
  59.         'editv set pctags_env_tagfiles '
  60.         'editv set pctags_return_arg '
  61.         'editv set pctags_file_spec '
  62.  
  63. * _init
  64.  
  65. ****************************************
  66. :alt-t
  67.  
  68. * Macro : pctags_auto
  69. * Syntax: Press the <Alt-T> key
  70. * Entry : None.  Callable from outside this module.
  71. * Exit  : '0' if entire retrieval operation was successfully completed
  72. *         '1' if operation was not successful.
  73. * Description:
  74. *         Complete RETRO operation is performed.
  75. *         Tagname is extracted from the current cursor position
  76. *         The cursor should be in the file area when this macro is invoked.  If
  77. *           the cursor is on the command line, the operation will abort.
  78. * Note  : This macro is assigned by default to the <Alt-T> keystroke.  You may
  79. *           reset this to any key you wish.
  80.  
  81.         * Make sure cursor is in file area and not on command line
  82.         if command() then do
  83.                 * Cursor cannot be on command line
  84.                 'emsg Cursor must be in file area'
  85.                 exit 1
  86.         end
  87.  
  88.         * Make sure cursor is under a valid word
  89.         'macro _delimiter' field.2()
  90.         if rc = 1 then do
  91.                 'emsg Cursor is not under a valid word'
  92.                 exit 1
  93.         end
  94.  
  95.         * Initialize global variables
  96.         'macro _init'
  97.  
  98.         * Save current cursor position
  99.         'sos save'
  100.  
  101.         * Backtrack to the start of the word (first delimiter or beginning
  102.         * of line)
  103.         do forever
  104.                 * If at beginning of line, stop backtracking
  105.                 if first() then
  106.                         leave
  107.  
  108.                 * Backtrack one character
  109.                 'cursor screen left'
  110.  
  111.                 * Check if character is a delimiter
  112.                 'macro _delimiter' field.2()
  113.                 if rc = 1 then do
  114.                         * Advance forward to first character in word and exit loop
  115.                         saved_rc = rc
  116.                         'cursor screen right'
  117.                 end
  118.  
  119.                 * If a delimiter was found, stop backtracking
  120.                 if saved_rc = '1' then
  121.                         leave
  122.         end
  123.  
  124.         * Grab characters until end of word
  125.         tagname = ''
  126.         do forever
  127.                 * Check if character is a delimiter
  128.                 'macro _delimiter' field.2()
  129.                 if rc = 1 then
  130.                         * Reached end of word, stop grabbing characters
  131.                         leave
  132.  
  133.                 * Append character to tagname
  134.                 tagname = tagname || field.2()
  135.  
  136.                 * Advance to next character
  137.                 'cursor screen right'
  138.         end
  139.  
  140.         * Restore original cursor position
  141.         'sos restore'
  142.  
  143.         * Append a blank to the tagname
  144.         tagname = tagname || ' '
  145.  
  146.         * Perform retrieval operation
  147.         'macro _pctags_main' tagname
  148.  
  149.         * Return appropriate value
  150.         'editv get pctags_return_arg'
  151.         if pctags_return_arg = 'SUCCESSFUL' then
  152.                 * Successful retrieval operation
  153.                 exit 0
  154.         else
  155.                 * Failed operation
  156.                 * Put cursor into file area
  157.                 if command() then
  158.                         'cursor home'
  159.                 exit 1
  160.  
  161. * pctags_auto
  162.  
  163. ****************************************
  164. :alt-p
  165.  
  166. * Macro : pctags_prompt
  167. * Syntax: Press the <Alt-P> key
  168. * Entry : None.  Callable from outside this module.
  169. * Exit  : Returns '0' if operation is successful, else '1'.
  170. * Description:
  171. *         Complete RETRO operation is performed.
  172. *         Tagname is prompted for on the message line and input on the
  173. *           command line.
  174. * Note  : This macro is assigned by default to the <Alt-P> keystroke.  You may
  175. *           reset this to any key you wish.
  176.  
  177.         * Initialize global variables
  178.         'macro _init'
  179.  
  180.         * Make sure the message line is active
  181.         'preserve'
  182.         'msgmode on'
  183.  
  184.         * Prompt the user for a tagname
  185.         'msg Enter tagname on command line'
  186.         'readv cmdline'
  187.  
  188.         * Restore original message mode
  189.         'restore'
  190.  
  191.         * If empty string was entered, abort
  192.         if readv.1 = '' then exit 1
  193.  
  194.         * Append a blank to the tagname
  195.         tagname = readv.1 || ' '
  196.  
  197.         * Perform retrieval operation
  198.         'macro _pctags_main' tagname
  199.  
  200.         * Return appropriate value
  201.         'editv get pctags_return_arg'
  202.         if pctags_return_arg = 'SUCCESSFUL' then
  203.                 * Successful retrieval operation
  204.                 exit 0
  205.         else
  206.                 * Failed operation
  207.                 * Put cursor into file area
  208.                 if command() then
  209.                         'cursor home'
  210.                 exit 1
  211.  
  212. * pctags_prompt
  213.  
  214. ****************************************
  215. :_delimiter
  216.  
  217. * Macro : _delimiter
  218. * Syntax: 'macro _delimiter' ch
  219. * Entry : ch is a single-character string
  220. * Exit  : If ch is a word delimiter (i.e. NOT an alphanumeric, underscore or
  221. *           period character) then return '1', else return '0'.
  222.  
  223.         * Get argument
  224.         ch = arg( 1 )
  225.  
  226.         * Check if delimiter
  227.         if ( ( datatype( ch, 'a' ) = '1' ) | ( ch = '_' ) | ( ch = '.' ) ) then do
  228.                 * No, it is not a delimiter
  229.                 exit 0
  230.         end
  231.  
  232.         * Yes, it is a delimiter
  233.         exit 1
  234.  
  235. * _delimiter
  236.  
  237. ****************************************
  238. :_convert_slashes
  239.  
  240. * Macro : _convert_slashes
  241. * Syntax: 'macro _convert_slashes' str
  242. * Entry : str is a complete file specification which may use slashes as path
  243. *           separators.
  244. * Exit  : All slash characters are converted to backslashes.  Converted string
  245. *           is returned in the global variable pctags_return_arg.
  246.  
  247.         * Get argument
  248.         str = arg( 1 )
  249.  
  250.         * Convert all slashes to backslashes
  251.         do forever
  252.                 * Look for a slash
  253.                 i = pos( '/', str )
  254.  
  255.                 * Convert slash to backslash
  256.                 if i <> 0 then
  257.                         str = substr( str, 1, i - 1 ) || '\' || substr( str, i + 1 )
  258.                 else
  259.                         leave
  260.         end
  261.  
  262.         * Return converted string
  263.         'editv set pctags_return_arg' str
  264.  
  265. * _convert_slashes
  266.  
  267. ****************************************
  268. :_dos_shell
  269.  
  270. * Macro : _dos_shell
  271. * Syntax: 'macro _dos_shell' file_spec
  272. * Entry : file_spec is the name of the file the RETROEXEC environment variable
  273. *           command is supposed to make available
  274. *         Global variable pctags_env_retroexec contains the command line to
  275. *           execute.  It may contain special parameters documented below.
  276. *           Case of the special parameters is significant.  It may also contain
  277. *           the DOS standard output redirection characters > or >>, but the
  278. *           command must then be bracketed with double quotes.  The quotes will
  279. *           be removed before sending the command line to DOS.
  280. * Exit  : The command will have been executed.  No return value is sent back.
  281. * Special command line parameters:
  282. *           %s - entire file specification of desired file (file_spec parm)
  283. *           %d - drive of desired file
  284. *           %p - path (no drive) of desired file (no terminating backslash)
  285. *           %f - filename of desired file
  286. *           %c - current directory (in drive:path format suitable for CD'ing)
  287. *           %u - user-defined substitution string
  288. *           %% - single %
  289.  
  290.         * Get arguments
  291.         cmd_line = arg( 1 )
  292.         'editv get pctags_file_spec'
  293.  
  294.         * If command line is bracketed by double quotes, remove them
  295.         if (substr( cmd_line, 1, 1 ) = '"') & (substr( cmd_line, length( cmd_line ), 1 ) = '"') then
  296.                 cmd_line = substr( cmd_line, 2, length( cmd_line ) - 2 )
  297.  
  298.         * Create special parameter strings
  299.         * Get drive:path
  300.         path_separator = pos( '\', pctags_file_spec )
  301.         do forever
  302.                 * If no more path separators found, exit do-loop
  303.                 if path_separator = '0' then leave
  304.  
  305.                 * Save position of found path separator
  306.                 last_path_separator = path_separator
  307.  
  308.                 * Look for another separator
  309.                 path_separator = pos( '\', pctags_file_spec, path_separator + 1 )
  310.         end
  311.  
  312.         * Save start of file name
  313.         fname_start = last_path_separator + 1
  314.  
  315.         * If not in root, don't count last backslash
  316.         if last_path_separator <> '3' then
  317.                 last_path_separator = last_path_separator - 1
  318.  
  319.         * Break drive:path into separate strings (%d and %p special parms)
  320.         drive = substr( pctags_file_spec, 1, 2 )
  321.         path  = substr( pctags_file_spec, 3, last_path_separator - 2 )
  322.  
  323.         * Get filename only (%f special parm)
  324.         fname = substr( pctags_file_spec, fname_start )
  325.  
  326.         * Get current directory
  327.         curr_dir = directory.1()
  328.  
  329.         * Parse command line, replacing special parameters
  330.         sub = pos( '%', cmd_line )
  331.         do forever
  332.                 * Was a special parameter found?
  333.                 if sub = '0' then leave
  334.  
  335.                 * Get the character after '%'
  336.                 parm = substr( cmd_line, sub + 1, 1 )
  337.  
  338.                 * Interpret substitution character
  339.                 sub_str = ''
  340.                 if parm = 's' then
  341.                         * Entire file specification of desired file
  342.                         sub_str = pctags_file_spec
  343.  
  344.                 if parm = 'd' then
  345.                         * Drive of desired file
  346.                         sub_str = drive
  347.  
  348.                 if parm = 'p' then
  349.                         * Path (no drive) of desired file
  350.                         sub_str = path
  351.  
  352.                 if parm = 'f' then
  353.                         * Filename of desired file
  354.                         sub_str = fname
  355.  
  356.                 if parm = 'c' then
  357.                         * Current directory
  358.                         sub_str = curr_dir
  359.  
  360.                 if parm = 'u' then do
  361.                         * User-defined substitution string
  362.                         'msg Enter substitution string on command line'
  363.                         'readv cmdline'
  364.                         sub_str = readv.1
  365.                 end
  366.  
  367.                 if parm = '%' then
  368.                         * Single percent sign
  369.                         sub_str = '%'
  370.  
  371.                 * Replace special parameter with substitution string
  372.                 cmd_line = substr( cmd_line, 1, sub - 1 ) || sub_str || substr( cmd_line, sub + 2 )
  373.  
  374.                 * Look for any more special parameters
  375.                 sub = pos( '%', cmd_line, sub + 1 )
  376.         end
  377.  
  378.         * Send command line to secondary command processor for execution
  379.         * Note: If you prefer, you may change this to a 'dosnowait' call
  380.         'dosquiet' cmd_line
  381.  
  382.         * Remove any output displayed onscreen during execution
  383.         'refresh'
  384.  
  385. * _dos_shell
  386.  
  387. ****************************************
  388. :_find_first
  389.  
  390. * Macro : _find_first
  391. * Syntax: 'macro _find_first' file_spec
  392. * Entry : file_spec is a file specification of the tagfile(s) which to search.
  393. *           It may contain wildcard characters.
  394. * Exit  : Global variable pctags_return_arg is set to the complete file
  395. *           specification of the first existing tagfile which to search.  If
  396. *           the returned string is empty then there are no existing files
  397. *           that match the input file_spec.
  398. * Note  : This macro creates a DIR.DIR file.  This file still exists when the
  399. *           macro exits and must be closed either by subsequent calls to this
  400. *           macro or by _pctags_main when a matching tagname is found.
  401. *         All the necessary checking to verify that the file can be created
  402. *           (i.e. the maximum number of files are not already open) is
  403. *           performed.  If the DIR.DIR file cannot be created because there is
  404. *           no room for it in the ring, the global variable pctags_return_arg
  405. *           is set to a value of NO_ROOM_IN_RING.  The calling macro must handle
  406. *           this appropriately.
  407. *         If a DIR.DIR file was not created because there were no matching file,
  408. *           an empty, dummy DIR.DIR is created.  This macro will always exit
  409. *           with a DIR.DIR file existing unless there is no room in the ring to
  410. *           hold it.
  411. *         If a DIR.DIR file already exists when this macro is called, it will be
  412. *           erased.
  413.  
  414.         * Get argument
  415.         file_spec = arg( 1 )
  416.  
  417.         * Try to create DIR.DIR file
  418.         'nomsg dir' file_spec
  419.  
  420.         * See if any matches exist
  421.         if rc <> 0 then do
  422.                 * No matches, see if DIR.DIR was created
  423.                 if rc = 95 | rc = 100 then do
  424.                         * Ran out of file space, DIR.DIR not created
  425.                         * Return NO_ROOM_IN_RING
  426.                         'editv set pctags_return_arg NO_ROOM_IN_RING'
  427.                         exit
  428.                 end
  429.  
  430.                 * DIR.DIR not created because no matches exist, create dummy
  431.                 * file and move to the end of it
  432.                 'nomsg kedit dir.dir (new noprofile'
  433.                 'locate 1'
  434.  
  435.                 * Return empty string
  436.                 'editv set pctags_return_arg '
  437.                 exit
  438.         end
  439.  
  440.         * DIR.DIR created, move from the top line to the first file line
  441.         'locate 1'
  442.  
  443.         * Return the complete fileid on this line
  444.         'editv set pctags_return_arg' dirfileid.1()
  445.  
  446. * _find_first
  447.  
  448. ****************************************
  449. :_find_next
  450.  
  451. * Macro : _find_next
  452. * Syntax: 'macro _find_next'
  453. * Entry : None.
  454. * Exit  : Global variable pctags_return_arg is set to the complete file
  455. *           specification of the next file matching the file_spec passed to
  456. *           the _find_first macro.  If there are no more matching files then
  457. *           an empty string is returned.
  458. *         This macro depends upon the DIR.DIR file being set by a previous call
  459. *           to _find_first.
  460. *         The DIR.DIR file will still exist upon exit from this macro, even if
  461. *           the end of the matching-file list was reached.
  462.  
  463.         * Make sure we're not already at the bottom of the list
  464.         if eof() then do
  465.                 * Return empty string
  466.                 * Note: This code should never be executed because the end-of-
  467.                 * the-list condition will have been found on a previous call.
  468.                 'editv set pctags_return_arg '
  469.                 exit
  470.         end
  471.  
  472.         * Move down to next line in matching-file list
  473.         'locate 1'
  474.  
  475.         * Return the complete fileid on this line
  476.         * Note: If we've reached to end-of-file line then the fileid should
  477.         * be empty
  478.         'editv set pctags_return_arg' dirfileid.1()
  479.  
  480. *  _find_next
  481.  
  482. ****************************************
  483. :_get_tagfile
  484.  
  485. * Macro : _get_tagfile
  486. * Syntax: 'macro _get_tagfile'
  487. * Entry : None.
  488. * Exit  : Global variable pctags_return_arg is set to the complete file
  489. *           specification of the next tagfile to search.  The tagfile is
  490. *           guaranteed to exist.  If the returned string is empty then there
  491. *           are no more tagfiles to search.
  492.  
  493.         * If this is the first call to this macro in this RETRO invocation,
  494.         * get the RETRO environment variable setting, if any
  495.         'editv get pctags_first_call'
  496.         if pctags_first_call = '0' then do
  497.                 * Get next matching file spec, if any
  498.                 'macro _find_next'
  499.                 'editv get pctags_return_arg'
  500.                 file_spec = pctags_return_arg
  501.         end; else do
  502.                 * Go thru this code once per RETRO invocation
  503.                 'editv set pctags_first_call 0'
  504.  
  505.                 * Get RETRO environment variable
  506.                 file_spec = dosenv( 'RETRO' )
  507.                 if file_spec = '' then do
  508.                         * No such variable, use the default
  509.                         file_spec = '*.tag'
  510.                 end
  511.  
  512.                 * Convert any slash path separators to backslashes
  513.                 'macro _convert_slashes' file_spec
  514.                 'editv get pctags_return_arg'
  515.                 file_spec = pctags_return_arg
  516.  
  517.                 * Parse any multiple file specs into single spec, may contain
  518.                 * wildcard characters
  519.                 'macro _parse_file_spec' file_spec
  520.                 'editv get pctags_return_arg'
  521.                 file_spec = pctags_return_arg
  522.  
  523.                 * Find the first matching file
  524.                 'macro _find_first' file_spec
  525.                 'editv get pctags_return_arg'
  526.                 file_spec = pctags_return_arg
  527.         end
  528.  
  529.         * Check if we have a tagfile name to search
  530.         do forever
  531.                 if file_spec <> '' then
  532.                         * We have a file spec, use it
  533.                         leave
  534.  
  535.                 * Are there more file specs in pctags_env_tagfiles?
  536.                 'editv get pctags_env_tagfiles'
  537.                 if pctags_env_tagfiles = '' then
  538.                         * No more tagfiles to search, return empty string
  539.                         leave
  540.  
  541.                 * Get the next tagfile spec, may contain wildcards
  542.                 'macro _parse_file_spec' pctags_env_tagfiles
  543.                 'editv get pctags_return_arg'
  544.                 file_spec = pctags_return_arg
  545.  
  546.                 * Find the first matching file
  547.                 'macro _find_first' file_spec
  548.                 'editv get pctags_return_arg'
  549.                 file_spec = pctags_return_arg
  550.         end
  551.  
  552.         * Verify that the _find_first macro was able to do its job
  553.         if file_spec = 'NO_ROOM_IN_RING' then do
  554.                 * Maximum number of files is already open
  555.                 'emsg Cannot open any more files'
  556.                 'editv set pctags_return_arg UNSUCCESSFUL'
  557.                 exit
  558.         end
  559.  
  560.         * Set return string
  561.         'editv set pctags_return_arg' file_spec
  562.  
  563. * _get_tagfile
  564.  
  565. ****************************************
  566. :_parse_file_spec
  567.  
  568. * Macro : _parse_file_spec
  569. * Syntax: 'macro _parse_file_spec' file_spec
  570. * Entry : file_spec is a file specification to parse.  May contain wildcards.
  571. *           May also contain multiple specs, each separated by a semicolon.
  572. * Exit  : The first file spec is returned in the pctags_return_arg global
  573. *           variable.  All subsequent file specs, if any, are stored in the
  574. *           global variable pctags_env_tagfiles.
  575.  
  576.         * Get argument
  577.         file_spec = arg( 1 )
  578.  
  579.         * Does file_spec contain multiple specs?
  580.         semicolon = pos( ';', file_spec )
  581.         if semicolon = 0 then
  582.                 * No, file_spec contains one drive:path\filename
  583.                 * Clear pctags_env_tagfiles
  584.                 'editv set pctags_env_tagfiles' ''
  585.         else do
  586.                 * Yes, store subsequent specs in pctags_env_tagfiles
  587.                 'editv set pctags_env_tagfiles' substr( file_spec, semicolon + 1 )
  588.  
  589.                 * Truncate subsequent specs from file_spec
  590.                 file_spec = substr( file_spec, 1, semicolon - 1 )
  591.         end
  592.  
  593.         * Return single file spec
  594.         'editv set pctags_return_arg' file_spec
  595.  
  596. * _parse_file_spec
  597.  
  598. ****************************************
  599. :_file_loaded
  600.  
  601. * Macro : _file_loaded
  602. * Syntax: 'macro _file_loaded' file_spec
  603. * Entry : file_spec is a complete file specification
  604. * Exit  : Global variable RC is set to '1' if file_spec is already loaded
  605. *           into a KEDIT buffer.  Otherwise it is set to '0'.
  606. *         If file is found to be loaded, it is made the current file.
  607.  
  608.         * Get argument
  609.         file_spec = arg( 1 )
  610.  
  611.         * Save the current fileid in case we have to return to it
  612.         org_fileid = fileid.1()
  613.  
  614.         * Try to make file_spec the current file
  615.         'nomsg kedit' file_spec '(new noprofile'
  616.  
  617.         * Did file exist in the ring?
  618.         if size.1() = '0' then do
  619.                 * No, delete empty file
  620.                 'quit'
  621.  
  622.                 * Return to original file
  623.                 'nomsg kedit' org_fileid '(new noprofile'
  624.  
  625.                 * Return 'not-loaded' value
  626.                 exit 0
  627.         end
  628.  
  629.         * File DID exist in ring, leave it as the current file
  630.         * Return 'already-loaded' value
  631.         exit 1
  632.  
  633. * _file_loaded
  634.  
  635. ****************************************
  636. :_save_dir_file
  637.  
  638. * Macro : _save_dir_file
  639. * Syntax: 'macro _save_dir_file'
  640. * Entry : None.
  641. * Exit  : If a DIR.DIR file exists in the ring, it is renamed to RETRO@@@.DIR.
  642. *         The current fileid upon entry to this macro remains unchanged upon
  643. *           exit.
  644. * Note  : Renaming the DIR.DIR file is necessary in order to preserve it through
  645. *           the RETRO macro.  RETRO creates several of its own DIR.DIR files
  646. *           which would overwrite any previously existing one.  It is necessary
  647. *           to rename the RETRO@@@.DIR file back to DIR.DIR before completing
  648. *           the RETRO operation.
  649.  
  650.         * Cycle thru ring of open files, searching for a DIR.DIR fileid
  651.         * Note: Always complete cycle, even after a DIR.DIR is found, so that
  652.         * we will return to the original file upon exit
  653.         do i = 1 to nbfile.1()
  654.                 * Compare this fileid to DIR.DIR
  655.                 if upper( fname.1() ) = 'DIR' & upper( fext.1() ) = 'DIR' then do
  656.                         * Rename file name to RETRO@@@.DIR
  657.                         'set fname RETRO@@@'
  658.                 end
  659.  
  660.                 * Advance to next file in ring
  661.                 'nomsg kedit'
  662.         end
  663.  
  664. * _save_dir_file
  665.  
  666. ****************************************
  667. :_restore_dir
  668.  
  669. * Macro : _restore_dir
  670. * Syntax: 'macro _restore_dir'
  671. * Entry : None.
  672. * Exit  : If a file called RETRO@@@.DIR exists in the ring of open files, it
  673. *           is renamed to DIR.DIR.
  674. * Note  : It is assumed that the RETRO@@@.DIR file was created by the macro
  675. *           _save_dir_file and did not exist when the RETRO operation began.
  676.  
  677.         * Cycle thru the ring of open files, searching for a RETRO@@@.DIR fileid
  678.         * Note: Always complete the cycle, even after RETRO@@@.DIR is found, so
  679.         * that we will return to the original file upon exit
  680.         do i = 1 to nbfile.1()
  681.                 * Compare this fileid to RETRO@@@.DIR
  682.                 if upper( fname.1() ) = 'RETRO@@@' & upper( fext.1() ) = 'DIR' then do
  683.                         * Rename file name to DIR.DIR
  684.                         'set fname DIR'
  685.                 end
  686.  
  687.                 * Advance to next file in ring
  688.                 'nomsg kedit'
  689.         end
  690.  
  691. * _restore_dir
  692.  
  693. ****************************************
  694. :_init_file
  695.  
  696. * Macro : _init_file
  697. * Syntax: 'macro _init_file'
  698. * Entry : None.
  699. * Exit  : Editor settings for the current file which would affect the outcome
  700. *           of our search are set so the search may succeed.
  701.  
  702.         * Set our own editor settings
  703.         'arbchar off'
  704.         'hex off'
  705.         'scope all'
  706.         'stay on'
  707.         'varblank off'
  708.         'wordwrap off'
  709.         'wrap on'
  710.         'zone 1 *'
  711.  
  712. * _init_file
  713.  
  714. ****************************************
  715. * Note: This descriptive section cannot be placed after the _pctags_main
  716. *       header because it would cause the macro to exceed the maximum macro
  717. *       length of 250 lines.
  718. *
  719. * Detailed Description:
  720. *    The main RETRO operation is performed.  This entails the following
  721. *    operations:
  722. *       -- Cycle through all required tagfiles.  Default = *.tag or all
  723. *            tagfiles specified in RETRO environment variable which may
  724. *            contain multiple file specs, each with wildcards, separated
  725. *            by semicolons.  For example,
  726. *               SET RETRO=c:\kedit\tagfiles\*.tag;c:\prog\*.tag
  727. *       -- Search each tagfile for the function_name string.
  728. *       -- If not found in any tagfile, display message and quit.
  729. *       -- If found, get name of file and definition file from tagfile.
  730. *       -- Close tagfile.
  731. *       -- Load file for editing.
  732. *       -- If file cannot be found, tag info contains EXEC command and
  733. *            environment variable RETROEXEC is defined, execute the
  734. *            command-line value assigned to it.  Try to load the file
  735. *            again.
  736. *       -- If file still cannot be found, display message and quit.
  737. *       -- Search file for definition line.
  738. *       -- If any of these operations fail, display appropriate error
  739. *            message and quit.
  740.  
  741. :_pctags_main
  742.  
  743. * Macro : _pctags_main
  744. * Syntax: 'macro _pctags_main' function_name
  745. * Entry : function_name is the tagname we are searching for.  A single blank
  746. *           character should be appended to its end.
  747. * Exit  : Global variable pctags_return_arg is set to SUCCESSFUL if the
  748. *           retrieval operation succeeds.  Otherwise, it is set to UNSUCCESSFUL.
  749. * Description:
  750. *         Main RETRO operation is performed.
  751.  
  752.         * Get argument
  753.         function_name = arg( 1 )
  754.  
  755.         * Create search-string (surround with @ characters)
  756.         search_tag = '@' || function_name || '@'
  757.  
  758.         * If a DIR.DIR file already exists, temporarily rename it
  759.         'macro _save_dir_file'
  760.  
  761.         * Cycle through all RETRO (or default) tagfiles until done or match found
  762.         do forever
  763.                 * Get a tagfile
  764.                 'macro _get_tagfile'
  765.                 'editv get pctags_return_arg'
  766.                 tagfile_name = pctags_return_arg
  767.  
  768.                 * If the maximum number of files are already open, quit
  769.                 * Note: Error handling was done in _get_tagfile
  770.                 if tagfile_name = 'UNSUCCESSFUL' then do
  771.                         'macro _restore_dir'
  772.                         exit
  773.                 end
  774.  
  775.                 * If no more tagfiles to get, quit
  776.                 if tagfile_name = '' then do
  777.                         * Tagname not found in tagfiles
  778.                         * Dump DIR.DIR file and terminate operation
  779.                         'quit'
  780.                         'emsg 'function_name'not found.'
  781.                         'macro _restore_dir'
  782.                         'editv set pctags_return_arg UNSUCCESSFUL'
  783.                         exit
  784.                 end
  785.  
  786.                 * Tagfile is guaranteed to exist so just try to load it
  787.                 'nomsg kedit' tagfile_name '(noprofile nodefext'
  788.  
  789.                 * Verify that there was room in the ring for the tagfile
  790.                 if rc <> 0 then do
  791.                         * See if we ran out of file space
  792.                         if rc = 95 | rc = 100 then
  793.                                 * Yes, max number of files already open
  794.                                 'emsg Cannot open any more files'
  795.                         else
  796.                                 * Could not load tagfile for some other reason
  797.                                 'emsg Could not load tagfile' tagfile_name
  798.  
  799.                         * Dump DIR.DIR file and terminate operation
  800.                         'quit'
  801.                         'macro _restore_dir'
  802.                         'editv set pctags_return_arg UNSUCCESSFUL'
  803.                         exit
  804.                 end
  805.  
  806.                 * Initialize tagfile
  807.                 'macro _init_file'
  808.                 'top'
  809.  
  810.                 * Set appropriate case-sensitivity for tagname search
  811.                 'editv get pctags_tagname_case'
  812.                 if pctags_tagname_case = 'CASE_SENSITIVE' then
  813.                         'case' case.1() 'respect'
  814.                 else
  815.                         'case' case.1() 'ignore'
  816.  
  817.                 * Search tagfile for function_name
  818.                 'nomsg tfind' search_tag
  819.                 if rc <> 0 then do
  820.                         * Tag not found, quit tagfile, try another
  821.                         'quit'
  822.                         iterate
  823.                 end
  824.  
  825.                 * Found a good match!
  826.                 * Leave tagfile-loop
  827.                 leave
  828.         end
  829.  
  830.         * Found a tagfile match
  831.         * Read tagfile line
  832.         line = curline.3()
  833.  
  834.         * Done with tagfile, close it
  835.         'quit'
  836.  
  837.         * Dump DIR.DIR file used for finding matching tagfile specs
  838.         'quit'
  839.  
  840.         * Format of line:
  841.         * Column 1: Function name searching for (variable length)
  842.         * Single space terminator
  843.         * Optional RETRO commands (! and #)
  844.         * Complete file specification of file containing definition
  845.         *   of function (variable length)
  846.         * Single space terminator
  847.         * Caret(^) character signifying the start of the definition line
  848.         * Line from file that defines the function or the line number in
  849.         *   the file
  850.         * As an example:
  851.         *   "function c:\dir\file.c ^int function( arg1, arg2 )"
  852.  
  853.         * Determine starting indices of file spec and definition line
  854.         file_start = pos( ' ', line ) + 1
  855.         decl_start = pos( ' ', line, file_start ) + 2
  856.  
  857.         * Extract file spec and definition line
  858.         file_spec = substr( line, file_start, decl_start - file_start - 2 )
  859.         decl_line = substr( line, decl_start )
  860.  
  861.         * Check file spec for leading command characters
  862.         exec_env      = '0'
  863.         line_number   = '0'
  864.         special_chars = '1'
  865.         do forever
  866.                 * Get a potential command char
  867.                 ch = substr( file_spec, special_chars, 1 )
  868.                 if ch = '!' then do
  869.                         * If file_spec not found, execute RETROEXEC
  870.                         * environment variable command line.
  871.                         exec_env = '1'
  872.  
  873.                         * Increment index
  874.                         special_chars = special_chars + 1
  875.                 end;
  876.                 if ch = '#' then do
  877.                         * Line number of definition is stored in tagfile
  878.                         * instead of line contents (99)
  879.                         line_number = '1'
  880.                         special_chars = special_chars + 1
  881.                 end
  882.                 if (ch <> '!') & (ch <> '#') then
  883.                         * Exit loop
  884.                         leave
  885.         end
  886.  
  887.         * Remove all leading command chars from file spec
  888.         file_spec = substr( file_spec, special_chars )
  889.  
  890.         * Save current fileid in case we have to return to it
  891.         original_fileid = fileid.1()
  892.  
  893.         * See if file is already loaded, make it current if it is
  894.         'macro _file_loaded' file_spec
  895.         file_already_loaded = rc
  896.  
  897.         * If file is not already loaded, verify that it exists
  898.         if file_already_loaded = '0' then do
  899.                 * See if file exists
  900.                 'nomsg dir' file_spec
  901.                 if rc = 0 then
  902.                         * File exists, dump DIR.DIR file
  903.                         'quit'
  904.                 else do
  905.                         * File not found, should we run RETROEXEC?
  906.                         if exec_env = '1' then do
  907.                                 * Yes, is RETROEXEC defined?
  908.                                 retroexec_env = dosenv( 'RETROEXEC' )
  909.                                 if retroexec_env <> '' then do
  910.                                         * Execute the variable's value
  911.                                         'editv set pctags_file_spec' file_spec
  912.                                         'macro _dos_shell' retroexec_env
  913.                                 end
  914.                         end
  915.  
  916.                         * Does file exist now?
  917.                         'nomsg dir' file_spec
  918.                         if rc = 0 then
  919.                                 * Yes, dump DIR.DIR
  920.                                 'quit'
  921.                         else do
  922.                                 * No, file is still not available
  923.                                 'emsg' file_spec 'does not exist.  Update tagfile.'
  924.  
  925.                                 * Nothing more we can do, return FAILURE code
  926.                                 'macro _restore_dir'
  927.                                 'editv set pctags_return_arg UNSUCCESSFUL'
  928.                                 exit
  929.                         end
  930.                 end
  931.  
  932.                 * Load source file (should never fail)
  933.                 'nomsg kedit' file_spec '(nodefext'
  934.         end
  935.  
  936.         * Turn on msgline (assumes PROFILE.KEX does not set msgmode off) and
  937.         * initialize file so our search will succeed, preserving original
  938.         * settings
  939.         'msgmode on'
  940.         'preserve'
  941.         'macro _init_file'
  942.  
  943.         * Restore any original DIR.DIR file
  944.         'macro _restore_dir'
  945.  
  946.         * Searching for line contents or line number?
  947.         if line_number = '1' then do
  948.                 * Goto specified line number in source file
  949.                 ':' || decl_line
  950.         end; else do
  951.                 * Search for definition line
  952.                 * Do not ignore case in search
  953.                 'case' case.1() 'respect'
  954.  
  955.                 * Surround definition string with @ characters
  956.                 decl_line = '@' || decl_line || '@'
  957.  
  958.                 * Do search operation
  959.                 'nomsg tfind' decl_line
  960.                 if rc <> 0 then do
  961.                         * Definition line not found in source file
  962.                         'restore'
  963.  
  964.                         * If file was loaded from disk, delete it
  965.                         if file_already_loaded = '0' then
  966.                                 'quit'
  967.                         else
  968.                                 * File was already loaded, go back to original fileid
  969.                                 'nomsg kedit' original_fileid '(new noprofile'
  970.  
  971.                         * Tell user what's going on
  972.                         'emsg Update' tagfile_name 'with' file_spec
  973.  
  974.                         'editv set pctags_return_arg UNSUCCESSFUL'
  975.                         exit
  976.                 end
  977.         end
  978.  
  979.         * Found function definition!
  980.         * Set SUCCESS return value
  981.         'restore'
  982.         'sos current'
  983.         'sos firstcol'
  984.         'editv set pctags_return_arg SUCCESSFUL'
  985.         exit
  986.  
  987. * _pctags_main
  988.  
  989. ****************************************
  990.