home *** CD-ROM | disk | FTP | other *** search
/ Programmer's ROM - The Computer Language Library / programmersrom.iso / ada / edit / ed2.src < prev    next >
Encoding:
Text File  |  1988-05-03  |  72.7 KB  |  2,129 lines

  1. ::::::::::
  2. ED2.ADA
  3. ::::::::::
  4.  
  5.  
  6. -------- SIMTEL20 Ada Software Repository Prologue ------------
  7. --                                                           -*
  8. -- Unit name    : EDITOR (ALED - Ada Line Editor)
  9. -- Version      : 2.1
  10. -- Author       : Richard Conn
  11. --              : Texas Instruments
  12. --              : PO Box 801, MS 8007
  13. --              : McKinney, TX  75069
  14. -- DDN Address  : RCONN at SIMTEL20
  15. -- Copyright    : (c) 1984, 1985 Richard Conn
  16. -- Date created :  9 Nov 84
  17. -- Release date :  5 Dec 84
  18. -- Last update  :  15 Feb 85
  19. -- Machine/System Compiled/Run on : DG MV 10000, ROLM ADE
  20. --              : All system-specific features are isolated in
  21. --        : the package SYSDEP, so I believe
  22. --              : that the editor is transportable between a
  23. --              : a wide variety of environments; I encountered
  24. --              : a number of "surprises" when I programmed the
  25. --              : editor, and I don't know if they were caused
  26. --              : by the ROLM ADE implementation of TEXT_IO or if
  27. --              : they were intentional; see the documentation
  28. --                                                           -*
  29. ---------------------------------------------------------------
  30. --                                                           -*
  31. -- Keywords     :  EDITOR
  32. ----------------:  LINE-ORIENTED EDITOR
  33. ----------------:  INPUT-LINE EDITOR
  34. --
  35. -- Abstract     :  ALED - Ada Line Editor
  36. ----------------:  A Line-Oriented File Editor Written in Ada
  37. ----------------:  by Richard Conn
  38. ----------------:  
  39. ----------------:  ALED is designed to edit text files.  Upon invocation,
  40. ----------------:  ALED prompts the user for a file name.  If the file
  41. ----------------:  exists, its contents (lines) are read in and prepared
  42. ----------------:  for editing; if the file does not exist, the file is
  43. ----------------:  created and the empty buffer is prepared for editing.
  44. ----------------:  ALED is an interactive editor, accepting single-char
  45. ----------------:  commands, filling in a command prompt (for more info
  46. ----------------:  as needed), and performing its functions in real-time
  47. ----------------:  while the user watches.  The functions provided include
  48. ----------------:  (but are not limited to) the following:
  49. ----------------:  
  50. ----------------:     * List Lines
  51. ----------------:     * Insert a Group of Lines into the Edit Buffer
  52. ----------------:     * Delete Lines
  53. ----------------:     * String Search and String Substitution
  54. ----------------:     * Movement Within the Edit Buffer
  55. ----------------:     * Reading in a File After a Specified Line
  56. ----------------:     * Writing out a Range of Lines to a File
  57. ----------------:     * Built-in, online Documentation (Summary)
  58. ----------------:  
  59. ----------------:  ALED's design includes an input line editor, which allows
  60. ----------------:  the user to edit text as he types it.  I was surprised
  61. ----------------:  NOT to find such a basic function available in TEXT_IO.
  62. ----------------:  Did I miss something?
  63. ----------------:  
  64. ----------------:  ALED is divided into the following files.  The order
  65. ----------------:  in which they are listed is the compilation order.
  66. ----------------:  
  67. ----------------:  SIMTEL20      Ada Package/Procedure  Comments
  68. ----------------:  
  69. ----------------:  SYSDEP.ADA     sysdep            Components library
  70. ----------------:                    of single-character
  71. ----------------:                    I/O routines
  72. ----------------:
  73. ----------------:  LIST.ADA      generic_list           Components library
  74. ----------------:                                       of linked-list routines
  75. ----------------:  
  76. ----------------:  ED-SPT.ADA    edit_support           Visible section
  77. ----------------:                                       of editor support
  78. ----------------:                                       package (which contains
  79. ----------------:                                       a few basic routines,
  80. ----------------:                                       such as the input line
  81. ----------------:                                       editor)
  82. ----------------:  
  83. ----------------:  ED-SPTB.ADA   edit_support           Body of editor support
  84. ----------------:                                       package
  85. ----------------:  
  86. ----------------:  ED-WRK.ADA    edit_worker            Visible seciton of
  87. ----------------:                                       workhorse routines
  88. ----------------:                                       for the editor;
  89. ----------------:                                       all major editor
  90. ----------------:                                       functions and their
  91. ----------------:                                       related support
  92. ----------------:                                       routines are here
  93. ----------------:                                       (such as list lines)
  94. ----------------:  
  95. ----------------:  ED-WRKB.ADA   edit_worker            Body of editor
  96. ----------------:                                       workhorse routines
  97. ----------------:  
  98. ----------------:  ED.ADA        editor                 Mainline of ALED
  99. ----------------:  
  100. ----------------:  
  101. --                                                           -*
  102. ------------------ Revision history ---------------------------
  103. --                                                           -*
  104. -- DATE         VERSION    AUTHOR                  HISTORY
  105. -- 12/5/84        1.0   Richard Conn            Initial Release
  106. -- 1/21/85        2.0   Richard Conn            Production version
  107. -- 2/15/85        2.1   Richard Conn            Minor bug fix
  108. --                                                           -*
  109. ------------------ Distribution and Copyright -----------------
  110. --                                                           -*
  111. -- This prologue must be included in all copies of this software.
  112. --
  113. -- This software is copyright by the author.
  114. --
  115. -- This software is released to the Ada community.
  116. -- This software is released to the Public Domain (note:
  117. --   software released to the Public Domain is not subject
  118. --   to copyright protection).
  119. -- Restrictions on use or distribution:  NONE
  120. --                                                           -*
  121. ------------------ Disclaimer ---------------------------------
  122. --                                                           -*
  123. -- This software and its documentation are provided "AS IS" and
  124. -- without any expressed or implied warranties whatsoever.
  125. -- No warranties as to performance, merchantability, or fitness
  126. -- for a particular purpose exist.
  127. --
  128. -- Because of the diversity of conditions and hardware under
  129. -- which this software may be used, no warranty of fitness for
  130. -- a particular purpose is offered.  The user is advised to
  131. -- test the software thoroughly before relying on it.  The user
  132. -- must assume the entire risk and liability of using this
  133. -- software.
  134. --
  135. -- In no event shall any person or organization of people be
  136. -- held responsible for any direct, indirect, consequential
  137. -- or inconsequential damages or lost profits.
  138. --                                                           -*
  139. -------------------END-PROLOGUE--------------------------------
  140.  
  141. -- 
  142. -- MAIN BODY OF ALED -- Ada Line Editor
  143. -- Program Written by Richard Conn, TI Ada Technology Branch
  144. -- Completion Date:  12/5/84
  145. -- Completion Date of 2.0:  1/31/85
  146. -- Completion Date of 2.1:  2/15/85
  147. -- 
  148.  
  149. -- 
  150. -- The following packages are used throughout the editor and constitute
  151. -- a set of basic support functions.
  152. -- 
  153. with TEXT_IO,
  154.      EDIT_SUPPORT,
  155.      EDIT_WORKER;
  156. use EDIT_SUPPORT, EDIT_WORKER;
  157.  
  158. -- 
  159. -- This is the main body of the editor
  160. -- 
  161. procedure EDITOR is
  162.     package NUM_IO is new TEXT_IO.INTEGER_IO (NATURAL);
  163.     VERSION_NUMBER      : constant := 21; -- major=2, minor=1
  164.     EDIT_FILE           : LINE_STRING;
  165.     FILE_NAME_LENGTH    : NATURAL;
  166.     NEW_STRING          : LINE_STRING;
  167.     SSTRING             : LINE_STRING;
  168.     DONE                : BOOLEAN;
  169.     RESP_CHAR, CMD_CHAR : CHARACTER;
  170.  
  171.     -- 
  172.     -- HELP_SUMMARY prints a summary of commands to the user
  173.     -- 
  174.     procedure HELP_SUMMARY is
  175.     begin
  176.         NEW_LINE;
  177.         NEW_LINE;
  178.         PUT ("--- Movement Commands ---  ");
  179.         PUT ("----- Enter Lines -----");
  180.         NEW_LINE;
  181.         PUT (" + Advance N Lines         ");
  182.         PUT (" A Append after <line> ");
  183.         NEW_LINE;
  184.         PUT (" - Back Up N Lines         ");
  185.         PUT (" I Insert before <line>");
  186.         NEW_LINE;
  187.         PUT (" F Find <string> in <range>");
  188.         PUT ("                       ");
  189.         NEW_LINE;
  190.         PUT (" J Jump to <line>          ");
  191.         PUT ("----- Print Lines -----");
  192.         NEW_LINE;
  193.         PUT (" N Find Next <string>      ");
  194.         PUT (" . Print Current Line  ");
  195.         NEW_LINE;
  196.         PUT ("----- Delete Command ----- ");
  197.         PUT (" < Print Next Line     ");
  198.         NEW_LINE;
  199.         PUT (" D Delete lines in <range> ");
  200.         PUT (" > Print Next Line     ");
  201.         NEW_LINE;
  202.         PUT ("                           ");
  203.         PUT (" L List over <range>   ");
  204.         NEW_LINE;
  205.         PUT ("---- Help and Exits ----   ");
  206.         PUT ("                       ");
  207.         NEW_LINE;
  208.         PUT (" H This Help Text          ");
  209.         PUT ("---- Substitution ---- ");
  210.         NEW_LINE;
  211.         PUT (" Q Quit without Updating   ");
  212.         PUT (" S String Substitute   ");
  213.         NEW_LINE;
  214.         PUT (" X Exit and Update         ");
  215.         PUT ("     over <range>      ");
  216.         NEW_LINE;
  217.         NEW_LINE;
  218.         PUT ("---- File Get/Put ----     ");
  219.         PUT ("-- Miscellaneous --    ");
  220.         NEW_LINE;
  221.         PUT (" G Get <file> after <line> ");
  222.         PUT (" ? Print Statistics    ");
  223.         NEW_LINE;
  224.         PUT (" P Put <file> over <range> ");
  225.         PUT ("                       ");
  226.         NEW_LINE;
  227.         NEW_LINE;
  228.         PUT ("<Range>:  %   %,%");
  229.         NEW_LINE;
  230.         PUT ("First or Second Entries --");
  231.         NEW_LINE;
  232.         PUT ("   #-Number, .-Current, C-Current, F-First,");
  233.         PUT (" L-Last");
  234.         NEW_LINE;
  235.         PUT ("Singular Entries --");
  236.         NEW_LINE;
  237.         PUT ("   A-All, P-Page");
  238.         NEW_LINE;
  239.     end HELP_SUMMARY;
  240.  
  241. -- 
  242. -- HELP prints help information to the user
  243. -- 
  244.     procedure HELP (INCHAR : CHARACTER) is
  245.     begin
  246.         NEW_LINE;
  247.         case INCHAR is
  248.             when 'c' | 'C' => 
  249.                 PUT ("Command Names:");
  250.                 NEW_LINE;
  251.                 PUT ("+ (Advance)     - (Backup)      . (Current)");
  252.                 NEW_LINE;
  253.                 PUT ("< (Previous)    > (Next)        ? (Statistics)");
  254.                 NEW_LINE;
  255.                 PUT ("Append  Delete  Find    Get     Help    Insert");
  256.                 NEW_LINE;
  257.                 PUT ("Jump    List    Next    Put     Quit    Substitute");
  258.                 NEW_LINE;
  259.                 PUT ("X(Exit)");
  260.                 NEW_LINE;
  261.             when 'n' | 'N' => 
  262.                 PUT ("Number Values:");
  263.                 NEW_LINE;
  264.                 PUT (". or C    Current Line");
  265.                 NEW_LINE;
  266.                 PUT ("  F       First Line");
  267.                 NEW_LINE;
  268.                 PUT ("  L       Last Line");
  269.                 NEW_LINE;
  270.                 PUT (" 25       Absolute Line Number");
  271.                 NEW_LINE;
  272.                 PUT ("+7 or -5  Relative Line Number");
  273.                 NEW_LINE;
  274.                 PUT ("  A       All Lines in File (only one argument)");
  275.                 NEW_LINE;
  276.                 PUT ("  P       Next Page of Lines (only one argument)");
  277.                 NEW_LINE;
  278.             when 's' | 'S' => 
  279.                 HELP_SUMMARY;
  280.             when others => 
  281.                 null;
  282.         end case;
  283.     end HELP;
  284.  
  285. -- 
  286. -- The mainline of the editor
  287. -- 
  288. begin
  289.     INITIALIZE_EDIT; -- initialize the Worker Functions
  290.     CONSOLE_INIT; -- initialize the console
  291. -- 
  292.     PUT ("ALED - Ada Line Editor by Richard Conn, Version ");
  293.     NUM_IO.PUT (VERSION_NUMBER / 10, 2);
  294.     PUT (".");
  295.     NUM_IO.PUT (VERSION_NUMBER mod 10, 1);
  296.     NEW_LINE;
  297. -- 
  298. -- Enter File Name and Trap All Exceptions as File Name Errors
  299. -- 
  300.     loop
  301.         begin
  302.             PUT ("File Name? ");
  303.             EDIT_FILE := INPUT_LINE;
  304.             SSTRING := EDIT_FILE; -- initial value for SSTRING
  305.             FILE_NAME_LENGTH := EDIT_FILE'LAST;
  306.             for I in 1 .. EDIT_FILE'LAST loop
  307.                 if EDIT_FILE (I) = ASCII.NUL then
  308.                     FILE_NAME_LENGTH := I - 1;
  309.                     exit;
  310.                 end if;
  311.             end loop;
  312.             READ_FILE (EDIT_FILE (1 .. FILE_NAME_LENGTH), TRUE);
  313.             exit; -- no exceptions raised
  314.         exception
  315.             when others => 
  316.                 NEW_LINE;
  317.                 PUT ("File Name Error -- ");
  318.         end;
  319.     end loop;
  320. -- 
  321.     NUM_IO.PUT (LAST_LINE, 5);
  322.     PUT (" Lines in File");
  323. -- 
  324.     COMMAND_GOTO (1); -- position at first line
  325.     NEW_LINE;
  326.     PUT (" Type H for Help");
  327.     DONE := FALSE; -- this flag indicates when the editor is to be exited
  328.     NEW_LINE;
  329. -- 
  330.     loop
  331.         begin
  332.             exit when DONE;
  333. -- 
  334. -- Print Prompt to User and Get Single-Char Command
  335. -- 
  336.             NUM_IO.PUT (CURRENT_LINE, 5);
  337.             PUT ("> ");
  338.             CMD_CHAR := GETCH; -- input command character without echo
  339. -- 
  340. -- Process Single-Char Commands
  341. -- 
  342.             case CMD_CHAR is
  343. -- 
  344. -- Null Commands (Just Echo New Line)
  345. -- 
  346.                 when ASCII.CR | ASCII.DEL | ASCII.BS => 
  347.                     NEW_LINE;
  348. -- 
  349. -- Print Current Line
  350. -- 
  351.                 when '.' => 
  352.                     NEW_LINE; -- no prompt
  353.                     LINE_START := CURRENT_LINE; -- list lines over current line
  354.                     LINE_STOP := CURRENT_LINE;
  355.                     COMMAND_LIST;
  356. -- 
  357. -- Backup and Print Previous Line
  358. -- 
  359.                 when '<' => 
  360.                     NEW_LINE; -- no prompt
  361.                     if CURRENT_LINE >= 1 then
  362.                         -- trap errors
  363.                         BACKUP_LINE;
  364.                     end if;
  365.                     LINE_START := CURRENT_LINE; -- list current line
  366.                     LINE_STOP := LINE_START;
  367.                     COMMAND_LIST;
  368. -- 
  369. -- Advance and Print Next Line
  370. -- 
  371.                 when '>' => 
  372.                     NEW_LINE; -- no prompt
  373.                     if CURRENT_LINE < LAST_LINE then
  374.                         -- trap errors
  375.                         ADVANCE_LINE;
  376.                     end if;
  377.                     LINE_START := CURRENT_LINE; -- list current line
  378.                     LINE_STOP := LINE_START;
  379.                     COMMAND_LIST;
  380. -- 
  381. -- Advance N Lines
  382. -- 
  383.                 when '+' => 
  384.                     PUT ("Advance N Lines <line count>");
  385.                     RANGE_INPUT;     -- pay attention to 1st value
  386.                     if CURRENT_LINE + LINE_START <= LAST_LINE then
  387.                         COMMAND_GOTO (CURRENT_LINE + LINE_START);
  388.                     else
  389.                         COMMAND_GOTO (LAST_LINE);
  390.                     end if;
  391. -- 
  392. -- Backup N Lines
  393. -- 
  394.                 when '-' => 
  395.                     PUT ("Back Up N Lines <line count>");
  396.                     RANGE_INPUT;     -- pay attention to 1st value
  397.                     if CURRENT_LINE - LINE_START < 1 then
  398.                         COMMAND_GOTO (1);
  399.                     else
  400.                         COMMAND_GOTO (CURRENT_LINE - LINE_START);
  401.                     end if;
  402. -- 
  403. -- Print Status Info
  404. -- 
  405.                 when '?' => 
  406.                     NEW_LINE; -- no prompt
  407.                     PUT ("       Edit File Name: ");
  408.                     OUTPUT_LINE (EDIT_FILE);
  409.                     NEW_LINE;
  410.                     PUT ("       ");
  411.                     NUM_IO.PUT (LAST_LINE, 5);
  412.                     PUT (" Lines in File");
  413.                     NEW_LINE;
  414. -- 
  415. -- Append a Group of Lines after the Indicated Line
  416. -- 
  417.                 when 'a' | 'A' => 
  418.                     PUT ("Append after <line>");
  419.                     RANGE_INPUT;     -- 1 or 2 args used
  420.                     if not BLANK_INPUT then
  421.                         -- abort if no input
  422.                         COMMAND_GOTO (LINE_START);
  423.                         COMMAND_APPEND;
  424.                     end if;
  425. -- 
  426. -- Delete a Group of Lines
  427. -- 
  428.                 when 'd' | 'D' => 
  429.                     PUT ("Delete lines in <range>");
  430.                     RANGE_INPUT;     -- 1 or 2 args used
  431.                     if not BLANK_INPUT then
  432.                         -- abort if no input
  433.                         COMMAND_DELETE;
  434.                     end if;
  435. -- 
  436. -- Find the First Occurrance of a String over a Range of Lines
  437. -- 
  438.                 when 'f' | 'F' => 
  439.                     PUT ("Find <string> ");
  440.                     SSTRING := INPUT_LINE;
  441.                     PUT ("        over <range>");
  442.                     RANGE_INPUT;     -- abort if no range input
  443.                     if not BLANK_INPUT then
  444.                         COMMAND_FIND (SSTRING);
  445.                         LINE_START := CURRENT_LINE;
  446.                         LINE_STOP := LINE_START;
  447.                         COMMAND_LIST;
  448.                     end if;
  449. -- 
  450. -- Load File into Current File After Indicated Line
  451. -- 
  452.                 when 'g' | 'G' => 
  453.                     PUT ("Get <file> ");
  454.                     SSTRING := INPUT_LINE;
  455.                     if not BLANK_INPUT then
  456.                         -- abort if no input
  457.                         PUT ("        after <line>");
  458.                         RANGE_INPUT;
  459.                         if not BLANK_INPUT then
  460.                             COMMAND_GET (SSTRING);
  461.                         end if;
  462.                     end if;
  463. -- 
  464. -- Print Help Message
  465. -- 
  466.                 when 'h' | 'H' => 
  467.                     PUT ("Help on the Following:");
  468.                     NEW_LINE;
  469.                     PUT ("          ");
  470.                     PUT ("C - Command Names, N - Numbering, S - Summary   > ");
  471.                     RESP_CHAR := GETCH_WITH_ECHO;
  472.                     HELP (RESP_CHAR); -- help routine above
  473. -- 
  474. -- Insert a Group of Lines Before the Indicated Line
  475. -- 
  476.                 when 'i' | 'I' => 
  477.                     PUT ("Insert before <line>");
  478.                     RANGE_INPUT;
  479.                     if not BLANK_INPUT then
  480.                         -- abort if no input
  481.                         COMMAND_GOTO (LINE_START);
  482.                         COMMAND_INSERT;
  483.                     end if;
  484. -- 
  485. -- Jump to a line
  486. -- 
  487.                 when 'j' | 'J' => 
  488.                     PUT ("Jump to <line>");
  489.                     RANGE_INPUT;
  490.                     if not BLANK_INPUT then
  491.                         -- abort if no input
  492.                         COMMAND_GOTO (LINE_START);
  493.                     end if;
  494. -- 
  495. -- List a Group of Lines Over a Range
  496. -- 
  497.                 when 'l' | 'L' => 
  498.                     PUT ("List Lines in <range>");
  499.                     RANGE_INPUT;
  500.                     if not BLANK_INPUT then
  501.                         -- abort if no input
  502.                         COMMAND_LIST;
  503.                     end if;
  504. -- 
  505. -- Find Next Occurrance of String
  506. -- 
  507.                 when 'n' | 'N' => 
  508.                     PUT ("Next Occurrance of <string> ");
  509.                     NEW_STRING := INPUT_LINE; -- get string
  510.                     if BLANK_INPUT then
  511.                         -- if no input
  512.                         NEW_STRING := SSTRING; -- use old string
  513.                     end if;
  514.                     LINE_START := CURRENT_LINE + 1; -- start at next line
  515.                     LINE_STOP := LAST_LINE;
  516.                     if LINE_START > LINE_STOP then
  517.                         LINE_START := LINE_STOP;
  518.                     end if;
  519.                     SSTRING := NEW_STRING; -- set old string
  520.                     COMMAND_FIND (SSTRING); -- search
  521.                     LINE_START := CURRENT_LINE; -- mark place and print
  522.                     LINE_STOP := LINE_START;
  523.                     COMMAND_LIST;
  524. -- 
  525. -- Write a Group of Lines Out to a File
  526. -- 
  527.                 when 'p' | 'P' => 
  528.                     PUT ("Put <file> ");
  529.                     SSTRING := INPUT_LINE;
  530.                     if not BLANK_INPUT then
  531.                         -- abort if no input
  532.                         PUT ("        over <range>");
  533.                         RANGE_INPUT;
  534.                         if not BLANK_INPUT then
  535.                             COMMAND_PUT (SSTRING);
  536.                         end if;
  537.                     end if;
  538. -- 
  539. -- Quit -- Exit Editor and Throw Away Contents
  540. -- 
  541.                 when 'q' | 'Q' => 
  542.                     PUT ("Quit without File Update (Y/N)? ");
  543.                     RESP_CHAR := GETCH_WITH_ECHO;
  544.                     if RESP_CHAR = 'y' or RESP_CHAR = 'Y' then
  545.                         DONE := TRUE;
  546.                     end if;
  547.                     NEW_LINE; -- CRLF is good, indicates activity
  548. -- 
  549. -- Substitute One String for Another Over a Range
  550. -- 
  551.                 when 's' | 'S' => 
  552.                     PUT ("Substitute for Old <string> ");
  553.                     SSTRING := INPUT_LINE;
  554.                     if not BLANK_INPUT then
  555.                         -- abort if no input
  556.                         PUT ("        New <string> ");
  557.                         NEW_STRING := INPUT_LINE;
  558.                         PUT ("        over <range>");
  559.                         RANGE_INPUT;
  560.                         if not BLANK_INPUT then
  561.                             COMMAND_SUBSTITUTE (SSTRING, NEW_STRING);
  562.                         end if;
  563.                     end if;
  564. -- 
  565. -- Exit Editor and Update File
  566. -- 
  567.                 when 'x' | 'X' => 
  568.                     PUT ("Exit and Update File (Y/N)? ");
  569.                     RESP_CHAR := GETCH_WITH_ECHO;
  570.                     if RESP_CHAR = 'y' or RESP_CHAR = 'Y' then
  571.                         DONE := TRUE;
  572.                     end if;
  573.                     NEW_LINE; -- CRLF shows activity
  574. -- 
  575. -- Invalid Command
  576. -- 
  577.                 when others => 
  578.                     PUT ("Error");
  579.                     NEW_LINE;
  580.             end case;
  581. -- 
  582. -- Exception Handlers
  583. -- 
  584.         exception
  585.             when RANGE_ERROR => 
  586.                 NEW_LINE;
  587.             when others => 
  588.                 NEW_LINE;
  589.                 PUT ("       Unknown Error Trapped");
  590.                 NEW_LINE;
  591. -- 
  592.         end;
  593.         -- command body
  594. -- 
  595.     end loop;
  596.  
  597. -- 
  598. -- Write File on Exit
  599. -- 
  600.     if CMD_CHAR = 'x' or CMD_CHAR = 'X' then
  601.         LINE_START := 1;         -- write file on way out
  602.         LINE_STOP := LAST_LINE;
  603.         COMMAND_PUT (EDIT_FILE);
  604.     end if;
  605. -- 
  606.     CONSOLE_DEINIT;   -- deinitialize the console
  607. -- 
  608. end EDITOR;
  609.  
  610.  
  611. ::::::::::
  612. ED2-SPT.ADA
  613. ::::::::::
  614.  
  615.  
  616. -- 
  617. -- PACKAGE edit_support
  618. --   by Richard Conn, TI Ada Technology Branch
  619. --   Version 1.0, 9 Nov 84
  620. --   Version 2.0, 29 Jan 85
  621. --   Version 2.1, 15 Feb 85
  622. -- 
  623. -- EDIT_SUPPORT provides a group of low-level support routines
  624. -- for the editor.  These are basic routines which can be used
  625. -- by programs other than the editor.
  626. -- 
  627. with GENERIC_LIST,
  628.      TEXT_IO;
  629. package EDIT_SUPPORT is
  630.  
  631. -- 
  632. -- The following establishes the basic set of types, objects,
  633. -- and linked-list manipulation and numeric I/O routines.
  634. -- 
  635.     LINE_LENGTH : constant := 256; -- allow 256 chars/line
  636.     subtype LINE_STRING is STRING (1 .. LINE_LENGTH);
  637.     package LINE_LIST is new GENERIC_LIST (ELEMENT_OBJECT => LINE_STRING);
  638.     package NAT_IO is new TEXT_IO.INTEGER_IO (NATURAL);
  639.  
  640. -- 
  641. -- The following are global values which are set by the low-level
  642. -- support routines.
  643. -- 
  644.  
  645. -- 
  646. -- BLANK_INPUT is set by the input line editor INPUT_LINE.
  647. -- If the line just input contained nothing but space characters
  648. -- (ie, is a blank line), INPUT_LINE sets BLANK_LINE to TRUE.
  649. -- Else, BLANK_LINE is FALSE.
  650. -- 
  651.     BLANK_INPUT : BOOLEAN := TRUE;
  652.  
  653. -- 
  654. -- VALID_NUMBER is set by the string-to-natural conversion routine
  655. -- CONVERT_TO_NUMBER.  If the string passed in does not begin with
  656. -- a valid digit character ('0' to '9'), VALID_NUMBER is set to FALSE
  657. -- and the value of 0 is returned by CONVERT_TO_NUMBER.  Else,
  658. -- VALID_NUMBER is set to TRUE and the converted number is returned.
  659. -- 
  660.     VALID_NUMBER : BOOLEAN := FALSE;
  661.  
  662. -- 
  663. -- CTN_INDEX is set by the caller of CONVERT_TO_NUMBER to tell it
  664. -- where to begin the conversion.  This number is the index
  665. -- of the first character at which to begin conversion.  On exit,
  666. -- CTN_INDEX is the index of the character at which conversion was
  667. -- halted.
  668. -- 
  669.     CTN_INDEX : NATURAL;
  670.  
  671. -- 
  672. -- The following are the workhorse routines of this package.
  673. -- 
  674.  
  675. -- 
  676. --      These routines initialize and deinitialize the
  677. -- console.  They should be called at the beginning and at
  678. -- the end of the edit session.
  679. -- 
  680.     procedure CONSOLE_INIT;
  681.     procedure CONSOLE_DEINIT;
  682.  
  683. -- 
  684. -- INPUT_LINE is a function which provides an input line editor.
  685. -- It accepts characters from the user until an end-of-line
  686. -- character is received, at which point INPUT_LINE terminates and
  687. -- returns an object of type LINE_STRING to the caller.  INPUT_LINE
  688. -- allows simple editing of the input text as it is typed, permitting
  689. -- the user to delete previous characters, delete input entered so
  690. -- far, retype the line as entered so far, and quote a character for
  691. -- literal input.  INPUT_LINE will not permit the limit of the input
  692. -- buffer to be exceeded.
  693. -- 
  694. --   BLANK_LINE is set to TRUE if only blank characters are
  695. -- contained in the line.
  696. -- 
  697. --   The following constants may be changed as desired:
  698. -- 
  699. --      Constant               Meaning
  700. --     EDIT_DEL_CHAR          Delete previous character in buffer
  701. --     EDIT_DEL_LINE          Restart buffer entry
  702. --     EDIT_RETYPE_LINE       Retype input line as entered so far
  703. --     EDIT_QUOTE             Quote following character
  704. -- 
  705.     function INPUT_LINE return LINE_STRING;
  706.  
  707. -- 
  708. --      Return next char without echo
  709. --      Return next char with echo if >= ' ' and < DEL
  710. -- 
  711.     function GETCH           return CHARACTER;
  712.     function GETCH_WITH_ECHO return CHARACTER;
  713.  
  714.  
  715. -- 
  716. --      Provides put string routine
  717. -- 
  718.     procedure PUT (INSTR : STRING);
  719.  
  720.  
  721. -- 
  722. --      Echo CRLF
  723. -- 
  724.     procedure NEW_LINE;
  725.  
  726.  
  727. -- 
  728. -- OUTPUT_LINE is a procedure which outputs an object of type
  729. -- LINE_STRING to the user's terminal.  Tab expansion is supported,
  730. -- and no trailing nulls are output.
  731. -- 
  732.     procedure OUTPUT_LINE (STR : LINE_STRING);
  733.  
  734.  
  735. -- 
  736. -- CONVERT_TO_NUMBER accepts as input an object of type
  737. -- LINE_STRING and converts the ASCII characters starting at
  738. -- the global index CTN_INDEX to a natural number.  The value
  739. -- of this number is returned, and CTN_INDEX is updated to
  740. -- indicate the index of the character which stopped the number
  741. -- scan.
  742. -- 
  743. --  VALID_NUMBER is set to TRUE if the first character is an
  744. -- ASCII digit character ('0' to '9'); VALID_NUMBER is set to
  745. -- FALSE if the first character is not a digit
  746. -- 
  747. --  CTN_INDEX is returned with the index of the character which
  748. -- stopped the scan/conversion process.
  749. -- 
  750.     function CONVERT_TO_NUMBER (STR : LINE_STRING) return NATURAL;
  751.  
  752. end EDIT_SUPPORT;
  753.  
  754.  
  755. ::::::::::
  756. ED2-SPTB.ADA
  757. ::::::::::
  758.  
  759.  
  760. -- 
  761. -- Package body EDIT_SUPPORT
  762. --  Written by Richard Conn, TI Ada Technology Branch
  763. --  Version 2.0, Date 31 Jan 85
  764. --  Version 2.1, Date 15 Feb 85
  765. -- 
  766.  
  767. with SYSDEP;
  768. package body EDIT_SUPPORT is
  769.  
  770. -- 
  771. -- Editor constants
  772. -- 
  773.     EDIT_DEL_CHAR    : constant CHARACTER := ASCII.DEL;
  774.     EDIT_DEL_LINE    : constant CHARACTER := ASCII.NAK;
  775.     EDIT_RETYPE_LINE : constant CHARACTER := ASCII.DC2;
  776.     EDIT_QUOTE       : constant CHARACTER := '\';
  777.     TAB_SIZE         : constant NATURAL := 8; -- for indenting
  778.  
  779. -- 
  780. -- Initialize console
  781. -- 
  782.     procedure CONSOLE_INIT is
  783.     begin
  784.         SYSDEP.OPEN_CONSOLE;
  785.     end CONSOLE_INIT;
  786.  
  787. -- 
  788. -- Deinitialize console
  789. -- 
  790.     procedure CONSOLE_DEINIT is
  791.     begin
  792.         SYSDEP.CLOSE_CONSOLE;
  793.     end CONSOLE_DEINIT;
  794.  
  795. -- 
  796. -- PRINTING_CHARACTER indicates if the character presented to it is printable
  797. -- (ie, occupies a position on the screen)
  798. -- 
  799.     function PRINTING_CHARACTER (INCHAR : CHARACTER) return BOOLEAN is
  800.     begin
  801.         if INCHAR >= ' ' and INCHAR < ASCII.DEL then
  802.             return TRUE;
  803.         else
  804.             return FALSE;
  805.         end if;
  806.     end PRINTING_CHARACTER;
  807.  
  808. -- 
  809. -- INPUT_LINE is the input line editor
  810. --  Customization can be done via the constant declarations
  811. -- 
  812.     function INPUT_LINE return LINE_STRING is
  813.  
  814.         WORK_LINE : LINE_STRING;
  815.         INCHAR    : CHARACTER;
  816.         INDEX     : NATURAL;
  817.         POSITION  : NATURAL;
  818.  
  819.         procedure BACKUP is -- erase previous character from display
  820.         begin
  821.             SYSDEP.PUT (ASCII.BS);
  822.             SYSDEP.PUT (' ');
  823.             SYSDEP.PUT (ASCII.BS);
  824.         end BACKUP;
  825.  
  826.         procedure BACKUP_CHARACTER is -- backup over last char w/tab processing
  827.             INCHAR          : CHARACTER;
  828.             BACKUP_POSITION : NATURAL;
  829.         begin
  830.             INCHAR := WORK_LINE (INDEX); -- extract target character
  831.             if INCHAR = ASCII.HT then
  832.                 -- back up over tab
  833.                 -- compute position prior to this tab
  834.                 POSITION := 1;
  835.                 for I in 1 .. INDEX - 1 loop
  836.                     if WORK_LINE (I) /= ASCII.HT then
  837.                         POSITION := POSITION + 1;
  838.                     else
  839.                         POSITION := POSITION + 1;
  840.                         while POSITION mod TAB_SIZE /= 1 loop
  841.                             POSITION := POSITION + 1;
  842.                         end loop;
  843.                     end if;
  844.                 end loop;
  845.                 -- BACKUP required number of character positions
  846.                 BACKUP_POSITION := POSITION;
  847.                 BACKUP;
  848.                 BACKUP_POSITION := BACKUP_POSITION + 1;
  849.                 while BACKUP_POSITION mod TAB_SIZE /= 1 loop
  850.                     BACKUP;
  851.                     BACKUP_POSITION := BACKUP_POSITION + 1;
  852.                 end loop;
  853.             else
  854. -- back up over normal char
  855.                 if PRINTING_CHARACTER (INCHAR) then
  856.                     -- printing char
  857.                     BACKUP;
  858.                     POSITION := POSITION - 1;
  859.                 end if;
  860.             end if;
  861.         end BACKUP_CHARACTER;
  862.  
  863.         procedure STORE_CHARACTER (INCHAR : CHARACTER) is -- store char
  864.         begin
  865.             if INDEX < WORK_LINE'LAST then
  866.                 -- room for char
  867.                 WORK_LINE (INDEX) := INCHAR;
  868.                 INDEX := INDEX + 1;
  869.             else
  870.                 -- no room
  871.                 SYSDEP.PUT (ASCII.BEL);  -- alarm
  872.             end if;
  873.         end STORE_CHARACTER;
  874.  
  875.     begin
  876.         INDEX := 1;
  877.         POSITION := 1;
  878.         loop
  879.             SYSDEP.GET (INCHAR);
  880.             exit when INCHAR = ASCII.CR;
  881.             case INCHAR is
  882.                 when EDIT_DEL_CHAR =>  -- delete previous character
  883.                     if INDEX /= 1 then
  884.                         INDEX := INDEX - 1;
  885.                         BACKUP_CHARACTER;
  886.                     else
  887.                         SYSDEP.PUT (ASCII.BEL);
  888.                     end if;
  889.                 when EDIT_DEL_LINE =>  -- delete line typed so far
  890.                     for I in 1 .. INDEX - 1 loop
  891.                         INDEX := INDEX - 1;
  892.                         BACKUP_CHARACTER;
  893.                     end loop;
  894.                     INDEX := 1;
  895.                     POSITION := 1;
  896.                 when EDIT_RETYPE_LINE =>  -- retype line input so far
  897.                     NEW_LINE; -- next line
  898.                     WORK_LINE (INDEX) := ASCII.NUL; -- mark end of line
  899.                     OUTPUT_LINE (WORK_LINE);
  900.                 when EDIT_QUOTE =>  -- quote next char
  901.                     SYSDEP.PUT (EDIT_QUOTE); -- echo EDIT_QUOTE char
  902.                     POSITION := POSITION + 1; -- EDIT_QUOTE is printing char
  903.                     SYSDEP.GET (INCHAR);    -- get quoted char
  904.                     STORE_CHARACTER (INCHAR);
  905.                     if PRINTING_CHARACTER (INCHAR) then
  906.                         SYSDEP.PUT (INCHAR); -- echo it
  907.                         POSITION := POSITION + 1;
  908.                     end if;
  909.                 when ASCII.HT =>  -- tabulate
  910.                     STORE_CHARACTER (INCHAR);
  911.                     SYSDEP.PUT (' ');
  912.                     POSITION := POSITION + 1;
  913.                     while POSITION mod TAB_SIZE /= 1 loop
  914.                         SYSDEP.PUT (' ');
  915.                         POSITION := POSITION + 1;
  916.                     end loop;
  917.                 when others =>  -- process next char
  918.                     STORE_CHARACTER (INCHAR); -- store char
  919.                     if PRINTING_CHARACTER (INCHAR) then
  920.                         SYSDEP.PUT (INCHAR);
  921.                         POSITION := POSITION + 1;
  922.                     end if;
  923.             end case;
  924.         end loop;
  925.         NEW_LINE;
  926. -- 
  927. -- NUL-fill line
  928. -- 
  929.         for I in INDEX .. WORK_LINE'LAST loop
  930.             WORK_LINE (I) := ASCII.NUL;
  931.         end loop;
  932. -- 
  933. -- test for empty line and set BLANK_INPUT
  934. -- 
  935.         BLANK_INPUT := TRUE;
  936.         for I in 1 .. INDEX loop
  937.             if WORK_LINE (I) > ' ' then
  938.                 BLANK_INPUT := FALSE;
  939.                 exit;
  940.             end if;
  941.         end loop;
  942. -- 
  943. -- return line
  944. -- 
  945.         return WORK_LINE;
  946. -- 
  947.     end INPUT_LINE;
  948.  
  949.  
  950. -- 
  951. -- OUTPUT_LINE outputs the string input to the user's terminal.
  952. -- 
  953.     procedure OUTPUT_LINE (STR : LINE_STRING) is
  954.  
  955.         INDEX    : NATURAL := 1;
  956.         POSITION : NATURAL := 1;
  957.  
  958.     begin
  959.         loop
  960.             exit when STR (INDEX) = ASCII.NUL;
  961.             if STR (INDEX) = ASCII.HT then
  962.                 -- tabulate
  963.                 SYSDEP.PUT (' ');
  964.                 POSITION := POSITION + 1;
  965.                 while (POSITION mod TAB_SIZE) /= 1 loop
  966.                     SYSDEP.PUT (' ');
  967.                     POSITION := POSITION + 1;
  968.                 end loop;
  969.             else
  970.                 -- output character
  971.                 SYSDEP.PUT (STR (INDEX));
  972.                 if PRINTING_CHARACTER (STR (INDEX)) then
  973.                     POSITION := POSITION + 1;
  974.                 end if;
  975.             end if;
  976.             INDEX := INDEX + 1;
  977.         end loop;
  978.     end OUTPUT_LINE;
  979.  
  980.  
  981. -- 
  982. -- GETCH returns the next character without echo
  983. -- GETCH_WITH_ECHO returns the next character with echo if
  984. --    ' ' <= ch < DEL
  985. -- 
  986.     function GETCH return CHARACTER is
  987.         INCHAR : CHARACTER;
  988.     begin
  989.         SYSDEP.GET (INCHAR);
  990.         return INCHAR;
  991.     end GETCH;
  992.  
  993.     function GETCH_WITH_ECHO return CHARACTER is
  994.         INCHAR : CHARACTER;
  995.     begin
  996.         INCHAR := GETCH;
  997.         if ' ' <= INCHAR and INCHAR < ASCII.DEL then
  998.             SYSDEP.PUT (INCHAR);
  999.         end if;
  1000.         return INCHAR;
  1001.     end GETCH_WITH_ECHO;
  1002.  
  1003.  
  1004. -- 
  1005. -- PUT outputs a string
  1006. -- 
  1007.     procedure PUT (INSTR : STRING) is
  1008.     begin
  1009.         for I in 1 .. INSTR'LAST loop
  1010.             SYSDEP.PUT (INSTR (I));
  1011.         end loop;
  1012.     end PUT;
  1013.  
  1014.  
  1015. -- 
  1016. -- NEW_LINE outputs CRLF to the console
  1017. -- 
  1018.     procedure NEW_LINE is
  1019.     begin
  1020.         SYSDEP.PUT (ASCII.CR);
  1021.         SYSDEP.PUT (ASCII.LF);
  1022.     end NEW_LINE;
  1023.  
  1024.  
  1025. -- 
  1026. -- CONVERT_TO_NUMBER converts the number represented by ASCII
  1027. -- digit chars to type NATURAL and returns its value.  VALID_NUMBER
  1028. -- and CTN_INDEX (an I/O value) are returned as side effects.
  1029. -- 
  1030.     function CONVERT_TO_NUMBER (STR : LINE_STRING) return NATURAL is
  1031.  
  1032.         INTERNAL_VALUE : NATURAL;
  1033.         INDEX          : NATURAL;
  1034.         DONE           : BOOLEAN;
  1035.  
  1036.         function IS_DIGIT (IN_CHAR : CHARACTER) return BOOLEAN is
  1037.         begin
  1038.             if IN_CHAR in '0' .. '9' then
  1039.                 return TRUE;
  1040.             else
  1041.                 return FALSE;
  1042.             end if;
  1043.         end IS_DIGIT;
  1044.  
  1045.     begin
  1046.         INTERNAL_VALUE := 0; -- set accumulated value
  1047.         INDEX := CTN_INDEX; -- set start index
  1048.  
  1049.         if IS_DIGIT (STR (INDEX)) then
  1050.             VALID_NUMBER := TRUE; -- input is a number
  1051.         else
  1052.             VALID_NUMBER := FALSE; -- input is not valid
  1053.             return 0; -- return value of 0
  1054.         end if;
  1055.  
  1056.         loop
  1057.             exit when not IS_DIGIT (STR (INDEX));
  1058.             case STR (INDEX) is
  1059.  
  1060.                 when '0'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 0;
  1061.  
  1062.                 when '1'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 1;
  1063.  
  1064.                 when '2'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 2;
  1065.  
  1066.                 when '3'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 3;
  1067.  
  1068.                 when '4'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 4;
  1069.  
  1070.                 when '5'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 5;
  1071.  
  1072.                 when '6'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 6;
  1073.  
  1074.                 when '7'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 7;
  1075.  
  1076.                 when '8'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 8;
  1077.  
  1078.                 when '9'    =>  INTERNAL_VALUE := INTERNAL_VALUE * 10 + 9;
  1079.  
  1080.                 when others =>  null; -- this will not be selected
  1081.             end case;
  1082.             INDEX := INDEX + 1;
  1083.         end loop;
  1084.  
  1085.         CTN_INDEX := INDEX; -- return index of invalid digit
  1086.         return INTERNAL_VALUE;
  1087.  
  1088.     exception
  1089.         when others =>  -- any type of numeric error trapped
  1090.             CTN_INDEX := INDEX; -- index set
  1091.             VALID_NUMBER := FALSE; -- not valid
  1092.             return 0; -- return 0 value
  1093.  
  1094.     end CONVERT_TO_NUMBER;
  1095.  
  1096. end EDIT_SUPPORT;
  1097.  
  1098.  
  1099. ::::::::::
  1100. ED2-WRK.ADA
  1101. ::::::::::
  1102.  
  1103.  
  1104. -- 
  1105. -- Package EDIT_WORKER
  1106. --  Written by Richard Conn, TI Ada Technology Branch
  1107. --  Version 2.0, Date 31 Jan 85
  1108. --  Version 2.1, Date 15 Feb 85
  1109. -- 
  1110.  
  1111. with TEXT_IO;
  1112. with EDIT_SUPPORT;
  1113. use EDIT_SUPPORT;
  1114. package EDIT_WORKER is
  1115.  
  1116. -- 
  1117. -- EDIT_WORKER is the set of procedures which implement the various
  1118. -- commands available through the EDITOR.  These are the workhorse
  1119. -- routines.
  1120. -- 
  1121.  
  1122. --===================================================================
  1123. -- 
  1124. -- The following global data buffers are used by several of the routines.
  1125. -- LINE_START and LINE_STOP are the numbers of the lines indicated by
  1126. -- input to RANGE_INPUT, and these values are set by RANGE_INPUT and read
  1127. -- by the routines which call RANGE_INPUT.  The exception RANGE_ERROR indicates
  1128. -- if there is an error in the input values received from RANGE_INPUT.
  1129. -- 
  1130.     LINE_START, LINE_STOP : NATURAL;
  1131.     RANGE_ERROR : exception;
  1132.  
  1133. --===================================================================
  1134. -- 
  1135. -- Procedure RANGE_INPUT
  1136. -- 
  1137. -- RANGE_INPUT is used to input a range specification of the following
  1138. -- forms:
  1139. --           x       -- reference a single line or one of the special ranges
  1140. --           x,x     -- reference a group of lines
  1141. --           x x     -- reference a group of lines (same as x,x)
  1142. -- 
  1143. -- A single line reference may be any of the following:
  1144. -- 
  1145. --    #    -- a line number, such as 1, 245, etc
  1146. --   +#    -- the line which is n lines after the current line, such as +23
  1147. --   -#    -- the line which is n lines before the current line, such as -45
  1148. --    A    -- all lines in the file
  1149. --    C    -- the current line
  1150. --    F    -- the first line
  1151. --    L    -- the last line
  1152. --    P    -- 20 consecutive lines, starting at the current line
  1153. -- 
  1154. -- A group of lines may be referenced by any combination of the following:
  1155. -- 
  1156. --    #   +#   -#   C   F   L
  1157. -- 
  1158. -- If the first entry of the pair references a line which is after the
  1159. -- line referenced by the second entry of the pair, then the RANGE_ERROR
  1160. -- flag will be raised.
  1161. -- 
  1162. -- EXCEPTIONS RAISED:  RANGE_ERROR
  1163. -- 
  1164. -- SIDE EFFECTS:
  1165. --  The values of LINE_START and LINE_STOP are always set.  If an error
  1166. -- is encountered, RANGE_ERROR is raised (error message is also printed).
  1167. -- 
  1168.  
  1169.     procedure RANGE_INPUT;
  1170.  
  1171.  
  1172. --===================================================================
  1173. -- 
  1174. -- The following routines return the indexes (natural numbers) of
  1175. -- the current and last lines (CURRENT_LINE, LAST_LINE) and advance
  1176. -- to the next line or backup to the previous line (ADVANCE_LINE,
  1177. -- BACKUP_LINE)
  1178. -- 
  1179.  
  1180.     function  CURRENT_LINE return NATURAL;
  1181.     function  LAST_LINE    return NATURAL;
  1182.     procedure ADVANCE_LINE;
  1183.     procedure BACKUP_LINE;
  1184.  
  1185.  
  1186. --===================================================================
  1187. -- 
  1188. -- The following file read routine is used to read the initial
  1189. -- file when the editor starts up
  1190. -- 
  1191.  
  1192.     procedure READ_FILE (FILE_NAME : STRING; CREATE_FLAG : BOOLEAN);
  1193.  
  1194.  
  1195.  
  1196. --===================================================================
  1197. -- 
  1198. -- The following routines implement the indicated commands:
  1199. -- 
  1200. --   ROUTINE NAME              COMMAND  MEANING OF COMMAND
  1201. --   initialize_edit                    Initialize the Editor
  1202. --   command_append               A     Append Lines After Current Line
  1203. --   command_delete               D     Delete One or More Lines
  1204. --   command_find                 F     Search for String
  1205. --   command_get                  G     Read in File after Current Line
  1206. --   command_goto                 J     Jump to (Position to) Indicated Line
  1207. --   command_insert               I     Insert Lines Before Current line
  1208. --   command_list                 L     List One or More Lines
  1209. --   command_put                  P     Write Out Range of Lines to File
  1210. --   command_substitute           S     Substitute Strings in One or More Lines
  1211. -- 
  1212.  
  1213.     procedure INITIALIZE_EDIT;
  1214.  
  1215.     procedure COMMAND_APPEND;
  1216.  
  1217.     procedure COMMAND_DELETE;
  1218.  
  1219.     procedure COMMAND_FIND (STR : EDIT_SUPPORT.LINE_STRING);
  1220.  
  1221.     procedure COMMAND_GET (FILE_NAME : EDIT_SUPPORT.LINE_STRING);
  1222.  
  1223.     procedure COMMAND_GOTO (NUM : NATURAL);
  1224.  
  1225.     procedure COMMAND_INSERT;
  1226.  
  1227.     procedure COMMAND_LIST;
  1228.  
  1229.     procedure COMMAND_PUT (FILE_NAME : EDIT_SUPPORT.LINE_STRING);
  1230.  
  1231.     procedure COMMAND_SUBSTITUTE
  1232.                  (OLD_STRING, NEW_STRING : EDIT_SUPPORT.LINE_STRING);
  1233.  
  1234. --===================================================================
  1235.  
  1236. end EDIT_WORKER;
  1237.  
  1238.  
  1239. ::::::::::
  1240. ED2_WRKB.ADA
  1241. ::::::::::
  1242.  
  1243.  
  1244. -- 
  1245. -- Package Body of EDIT_WORKER
  1246. -- by Richard Conn, Texas Instruments, Ada Technology Branch
  1247. -- Version 1.0, Date 20 Nov 84
  1248. -- Version 2.0, Date 31 Jan 85
  1249. -- Version 2.1, Date 15 Feb 85
  1250. -- 
  1251. -- 
  1252. -- This package contains all of the procedures which implement
  1253. -- the major commands of the editor.  EDIT_WORKER is divided into
  1254. -- functional sections (more or less), with each section separated
  1255. -- from the others by lines like "--=============".
  1256. -- 
  1257. -- The package is divided into the following sections:
  1258. -- 
  1259. -- SECTION              FUNCTION
  1260. -- Package NUM_IO       Provide numeric output for NATURAL numbers
  1261. -- RANGE_INPUT          Provide general-purpose line range input
  1262. -- CURRENT_LINE         Returns the number of the current line
  1263. -- LAST_LINE            Returns the number of the last line
  1264. -- ADVANCE_LINE         Advances to the next line
  1265. -- BACKUP_LINE          Back ups to the last line
  1266. -- Line Output          Print lines and info to the terminal
  1267. --   INPUT_LINE_PROMPT
  1268. --   NUMBER_PREFIX
  1269. --   PREFIX_PRINT
  1270. -- COMMAND_GOTO         Implements the Jump (J) Command and Used Internally
  1271. -- COMMAND_APPEND       Implements the Append (A) Command
  1272. -- COMMAND_INSERT       Implements the Insert (I) Command
  1273. -- COMMAND_LIST         Implements the List (L) Command
  1274. -- COMMAND_DELETE       Implements the Delete (D) Command
  1275. -- Scanning Aids        Lower-level functions/procedures for Substitute
  1276. --   SUB_STRING           and Find
  1277. --   COUNT_CHARS
  1278. --   SUBSTITUTE
  1279. -- COMMAND_SUBSTITUTE   Implements the Substitute (S) Command
  1280. -- COMMAND_FIND         Implements the Find (F) Command
  1281. -- GET and PUT Support  Routines to Support File Input/Output
  1282. --   WRITE_FLINE
  1283. --   PUT_RANGE
  1284. --   READ_FILE
  1285. -- COMMAND_GET          Implements the Get (G) Command
  1286. -- COMMAND_PUT          Implements the Put (P) Command
  1287. -- 
  1288.  
  1289. with TEXT_IO;
  1290. with EDIT_SUPPORT;
  1291. use EDIT_SUPPORT;
  1292.  
  1293. package body EDIT_WORKER is
  1294.  
  1295. -- 
  1296. -- LINE_EXIT_CHAR is the character which, when it appears as the first
  1297. -- character of a line and it is the only character on that line, indicates
  1298. -- that the last line has been input for the Append and Insert Commands.
  1299. -- 
  1300.     LINE_EXIT_CHAR : constant CHARACTER := '.';
  1301.  
  1302. --===================================================================
  1303. -- Package NUM_IO
  1304. --     Generic Instantiation of TEXT_IO.INTEGER_IO for NATURAL numbers
  1305. -- 
  1306.     package NUM_IO is new TEXT_IO.INTEGER_IO (NATURAL);
  1307.  
  1308. --===================================================================
  1309. -- RANGE_INPUT inputs one or two values, and it always returns with
  1310. -- LINE_START containing the first value and LINE_STOP containing the
  1311. -- second.  LINE_START <= LINE_STOP, and if there was any error in
  1312. -- the input, the exception RANGE_ERROR is raised
  1313. -- 
  1314.     procedure RANGE_INPUT is
  1315.  
  1316.         INTERNAL_ERROR : exception;
  1317.         PAGE_SIZE  : constant NATURAL := 20; -- number of lines/"page"
  1318.         RANGE_LINE : LINE_STRING;
  1319.         I          : NATURAL; -- index of next char in input line
  1320.         DONE       : BOOLEAN := FALSE;
  1321.  
  1322. -- 
  1323. -- Local procedure FLUSH_SPACES - skip over spaces until non-space,
  1324. -- including end-of-line (ASCII.nul), is encountered
  1325. -- 
  1326.         procedure FLUSH_SPACES is
  1327.         begin
  1328.             loop
  1329.                 exit when RANGE_LINE (I) /= ' ';
  1330.                 I := I + 1;
  1331.             end loop;
  1332.         end FLUSH_SPACES;
  1333.  
  1334. -- 
  1335. -- The body of RANGE_INPUT
  1336. -- 
  1337.     begin
  1338.         I := 1; -- index of first char
  1339.         PUT (" "); -- space (prompt)
  1340.         RANGE_LINE := INPUT_LINE; -- input line (with editing)
  1341.         if BLANK_INPUT then
  1342.             LINE_START := LINE_LIST.CURRENT_INDEX; -- set first and last to .
  1343.             LINE_STOP := LINE_START;
  1344.             return; -- done
  1345.         end if;
  1346.  
  1347.         FLUSH_SPACES; -- get rid of leading spaces
  1348.  
  1349. -- 
  1350. -- Check for an process the First Argument
  1351. -- 
  1352.         case RANGE_LINE (I) is
  1353. -- first of one or two arguments
  1354.             when '+' =>  -- current line + offset
  1355.                 CTN_INDEX := I + 1; -- set starting index
  1356.                 LINE_START := LINE_LIST.CURRENT_INDEX +
  1357.                               CONVERT_TO_NUMBER (RANGE_LINE);
  1358.                 LINE_STOP := LINE_START;
  1359.                 I := CTN_INDEX; -- restore index
  1360.             when '-' =>  -- current line - offset
  1361.                 CTN_INDEX := I + 1; -- set starting index
  1362.                 LINE_START := LINE_LIST.CURRENT_INDEX -
  1363.                               CONVERT_TO_NUMBER (RANGE_LINE);
  1364.                 LINE_STOP := LINE_START;
  1365.                 I := CTN_INDEX; -- restore index
  1366.             when 'a' | 'A' =>  -- all lines
  1367.                 LINE_START := 1;
  1368.                 LINE_STOP := LINE_LIST.LAST_INDEX;
  1369.                 I := I + 1; -- next char
  1370.             when 'c' | 'C' | '.' =>  -- current line
  1371.                 LINE_START := LINE_LIST.CURRENT_INDEX;
  1372.                 LINE_STOP := LINE_START;
  1373.                 I := I + 1; -- next char
  1374.             when 'f' | 'F' =>  -- first line
  1375.                 LINE_START := 1;
  1376.                 LINE_STOP := LINE_START;
  1377.                 I := I + 1; -- next char
  1378.             when 'l' | 'L' =>  -- last line
  1379.                 LINE_START := LINE_LIST.LAST_INDEX;
  1380.                 LINE_STOP := LINE_START;
  1381.                 I := I + 1; -- next char
  1382.             when 'p' | 'P' =>  -- page
  1383.                 LINE_START := LINE_LIST.CURRENT_INDEX;
  1384.                 if LINE_START + PAGE_SIZE > LINE_LIST.LAST_INDEX then
  1385.                     LINE_STOP := LINE_LIST.LAST_INDEX;
  1386.                 else
  1387.                     LINE_STOP := LINE_START + PAGE_SIZE;
  1388.                 end if;
  1389.                 I := I + 1; -- next char
  1390.             when '0' .. '9' => 
  1391.                 CTN_INDEX := I;
  1392.                 LINE_START := CONVERT_TO_NUMBER (RANGE_LINE);
  1393.                 LINE_STOP := LINE_START;
  1394.                 I := CTN_INDEX;
  1395.             when others => 
  1396.                 raise INTERNAL_ERROR;
  1397.         end case;
  1398.  
  1399. -- 
  1400. -- Check for possible range errors
  1401. -- 
  1402.         if LINE_START > LINE_LIST.LAST_INDEX then  raise RANGE_ERROR;  end if;
  1403.         if LINE_STOP > LINE_LIST.LAST_INDEX then  raise RANGE_ERROR;  end if;
  1404.  
  1405. -- 
  1406. -- Advance to next token
  1407. -- 
  1408.         FLUSH_SPACES; -- flush spaces between entires
  1409.  
  1410. -- 
  1411. -- Done if no next token
  1412. -- 
  1413.         if RANGE_LINE (I) = ASCII.NUL then
  1414.             return;
  1415.         end if;
  1416.  
  1417. -- 
  1418. -- If a comma is present, a second argument is given
  1419. -- 
  1420.         if RANGE_LINE (I) = ',' then
  1421.             I := I + 1;
  1422.             FLUSH_SPACES;
  1423.             if RANGE_LINE (I) = ASCII.NUL then
  1424.                 raise INTERNAL_ERROR;
  1425.             end if;
  1426.         end if;
  1427.  
  1428. -- 
  1429. -- Process Second Argument of an argument pair
  1430. -- The value of this argument is assigned to LINE_STOP
  1431. -- 
  1432.         case RANGE_LINE (I) is
  1433. -- second of two arguments
  1434.             when '+' =>  -- current line + offset
  1435.                 CTN_INDEX := I + 1;
  1436.                 LINE_STOP := LINE_LIST.CURRENT_INDEX +
  1437.                              CONVERT_TO_NUMBER (RANGE_LINE);
  1438.                 I := CTN_INDEX;
  1439.             when '-' =>  -- current line - offset
  1440.                 CTN_INDEX := I + 1;
  1441.                 LINE_STOP := LINE_LIST.CURRENT_INDEX -
  1442.                              CONVERT_TO_NUMBER (RANGE_LINE);
  1443.                 I := CTN_INDEX;
  1444.             when 'c' | 'C' | '.' =>  -- current line
  1445.                 LINE_STOP := LINE_LIST.CURRENT_INDEX;
  1446.             when 'f' | 'F' =>  -- first line
  1447.                 LINE_STOP := 1;
  1448.             when 'l' | 'L' =>  -- last line
  1449.                 LINE_STOP := LINE_LIST.LAST_INDEX;
  1450.             when '0' .. '9' => 
  1451.                 CTN_INDEX := I;
  1452.                 LINE_STOP := CONVERT_TO_NUMBER (RANGE_LINE);
  1453.                 I := CTN_INDEX;
  1454.             when others => 
  1455.                 raise INTERNAL_ERROR;
  1456.         end case;
  1457.  
  1458. -- 
  1459. -- Check out possible range errors
  1460. -- 
  1461.         if LINE_STOP > LINE_LIST.LAST_INDEX then  raise RANGE_ERROR;  end if;
  1462.  
  1463. -- 
  1464. -- Handle Exceptions Raised within the procedure RANGE_INPUT
  1465. -- 
  1466.     exception
  1467.         when NUMERIC_ERROR => 
  1468.             NEW_LINE;
  1469.             PUT ("       Numeric Value Error");
  1470.             LINE_START := 0;
  1471.             LINE_STOP := 0;
  1472.             raise RANGE_ERROR;
  1473.         when INTERNAL_ERROR => 
  1474.             NEW_LINE;
  1475.             PUT ("       Range Syntax Error");
  1476.             LINE_START := 0;
  1477.             LINE_STOP := 0;
  1478.             raise RANGE_ERROR;
  1479.         when RANGE_ERROR => 
  1480.             NEW_LINE;
  1481.             PUT ("       Range Value Error");
  1482.             LINE_START := 0;
  1483.             LINE_STOP := 0;
  1484.             raise RANGE_ERROR;
  1485.         when others => 
  1486.             NEW_LINE;
  1487.             PUT ("       Unknown Error in RANGE_INPUT");
  1488.             LINE_START := 0;
  1489.             LINE_STOP := 0;
  1490.             raise RANGE_ERROR;
  1491.  
  1492.     end RANGE_INPUT;
  1493.  
  1494.  
  1495. --===================================================================
  1496. -- 
  1497. -- CURRENT_LINE
  1498. -- This function returns the number of the current line
  1499. -- 
  1500.  
  1501.     function CURRENT_LINE return NATURAL is
  1502.     begin
  1503.         return LINE_LIST.CURRENT_INDEX;
  1504.     end CURRENT_LINE;
  1505.  
  1506.  
  1507. --===================================================================
  1508. -- 
  1509. -- LAST_LINE
  1510. -- This function returns the number of the last line
  1511. -- 
  1512.  
  1513.     function LAST_LINE return NATURAL is
  1514.     begin
  1515.         return LINE_LIST.LAST_INDEX;
  1516.     end LAST_LINE;
  1517.  
  1518.  
  1519. --===================================================================
  1520. -- 
  1521. -- ADVANCE_LINE
  1522. -- This function advances the current line by one
  1523. -- 
  1524.  
  1525.     procedure ADVANCE_LINE is
  1526.         DUMMY : BOOLEAN;
  1527.     begin
  1528.         DUMMY := LINE_LIST.CURRENT_NEXT;
  1529.     end ADVANCE_LINE;
  1530.  
  1531.  
  1532. --===================================================================
  1533. -- 
  1534. -- BACKUP_LINE
  1535. -- This procedure back ups the current line by one
  1536. -- 
  1537.  
  1538.     procedure BACKUP_LINE is
  1539.         DUMMY : BOOLEAN;
  1540.     begin
  1541.         DUMMY := LINE_LIST.CURRENT_PREVIOUS;
  1542.     end BACKUP_LINE;
  1543.  
  1544.  
  1545.  
  1546. --===================================================================
  1547. -- 
  1548. -->> Procedure INPUT_LINE_PROMPT
  1549. -- This procedure simply prints the prompt for the Append and Insert
  1550. --  commands.
  1551. -- 
  1552.  
  1553.     procedure INPUT_LINE_PROMPT is
  1554.     begin
  1555.         PUT ("Enter Lines (");
  1556.         TEXT_IO.PUT (LINE_EXIT_CHAR);
  1557.         PUT ("<RETURN> to Stop)");
  1558.         NEW_LINE;
  1559.     end INPUT_LINE_PROMPT;
  1560.  
  1561. -- 
  1562. -->> Procedure NUMBER_PREFIX
  1563. -- This routine prints the prefix number ("nnnnn: ") for lines
  1564. --  that are displayed or input.
  1565. -- 
  1566.     procedure NUMBER_PREFIX (NUM : NATURAL) is
  1567.     begin
  1568.         NUM_IO.PUT (INTEGER (NUM), 5); -- 5-char field
  1569.         PUT (": "); -- trailing prompt
  1570.     end NUMBER_PREFIX;
  1571.  
  1572. -- 
  1573. -->> Procedure PREFIX_PRINT
  1574. -- This routine prints a line prefixed by a number ("nnnnn: text").
  1575. -- 
  1576.     procedure PREFIX_PRINT (NUM : NATURAL; STR : LINE_STRING) is
  1577.     begin
  1578.         NUMBER_PREFIX (NUM);
  1579.         OUTPUT_LINE (STR);
  1580.     end PREFIX_PRINT;
  1581.  
  1582. --===================================================================
  1583. -- Procedure INITIALIZE_EDIT
  1584. -- This procedure initializes the editor for future processing
  1585. -- 
  1586.     procedure INITIALIZE_EDIT is
  1587.     begin
  1588.         LINE_LIST.INITIALIZE_LIST;
  1589.     end INITIALIZE_EDIT;
  1590.  
  1591.  
  1592. --===================================================================
  1593. -- Procedure COMMAND_GOTO
  1594. -- This procedure positions the current line to the indicated index.
  1595. -- That is, if NUM = 5, the fifth line in the file becomes the current line.
  1596. -- 
  1597.     procedure COMMAND_GOTO (NUM : NATURAL) is
  1598.         I     : NATURAL;
  1599.         DUMMY : BOOLEAN;
  1600.     begin
  1601.         if NUM <= LINE_LIST.LAST_INDEX then
  1602.             I := NUM;
  1603.         else
  1604.             I := LINE_LIST.LAST_INDEX;
  1605.         end if;
  1606.         DUMMY := LINE_LIST.SET_CURRENT_INDEX (I); -- return code is a don't care
  1607.     end COMMAND_GOTO;
  1608.  
  1609. --===================================================================
  1610. -- Procedure COMMAND_APPEND
  1611. -- This procedure implements the Append command.  It accepts a group of
  1612. -- lines one at a time, appends the new line after the current line, makes
  1613. -- the new line the current line, and continues until a line consisting of
  1614. -- only a LINE_EXIT_CHAR is input.
  1615. -- 
  1616.     procedure COMMAND_APPEND is
  1617.         INLINE : LINE_STRING;
  1618.     begin
  1619.         INPUT_LINE_PROMPT; -- print prompt
  1620.         loop
  1621.             NUMBER_PREFIX (LINE_LIST.CURRENT_INDEX + 1); -- print number of line
  1622.             INLINE := INPUT_LINE; -- get input line
  1623.             exit when (INLINE (1) = LINE_EXIT_CHAR) and
  1624.                       (INLINE (2) = ASCII.NUL); -- test for exit condition
  1625.             LINE_LIST.APPEND_ELEMENT (INLINE); -- append line after current
  1626.         end loop;
  1627.     end COMMAND_APPEND;
  1628.  
  1629. --===================================================================
  1630. -- Procedure COMMAND_INSERT
  1631. -- This procedure is like COMMAND_APPEND, but the input lines are inserted
  1632. -- before the current line.
  1633. -- 
  1634.     procedure COMMAND_INSERT is
  1635.         INLINE : LINE_STRING;
  1636.     begin
  1637.         INPUT_LINE_PROMPT; -- print prompt
  1638.         loop
  1639.             NUMBER_PREFIX (LINE_LIST.CURRENT_INDEX); -- print line number
  1640.             INLINE := INPUT_LINE; -- get new line
  1641.             exit when (INLINE (1) = LINE_EXIT_CHAR) and
  1642.                       (INLINE (2) = ASCII.NUL); -- test for exit condition
  1643.             LINE_LIST.INSERT_ELEMENT (INLINE); -- perform insertion
  1644.         end loop;
  1645.     end COMMAND_INSERT;
  1646.  
  1647. --===================================================================
  1648. -- Procedure COMMAND_LIST
  1649. -- This procedure lists a group of lines over a range.  The range is
  1650. -- indicated by the global variables LINE_START and LINE_STOP, which are
  1651. -- set by the RANGE_INPUT routine and may be set by other routines as well.
  1652. -- 
  1653.     procedure COMMAND_LIST is
  1654.         I     : NATURAL;
  1655.         DUMMY : BOOLEAN;
  1656.     begin
  1657.         COMMAND_GOTO (LINE_START); -- position at first line
  1658.         for I in 1 .. LINE_STOP - LINE_START + 1 loop
  1659.             -- over lines in range
  1660.             PREFIX_PRINT (LINE_LIST.CURRENT_INDEX,
  1661.                           LINE_LIST.RETURN_CURRENT_ELEMENT); -- print line
  1662.             NEW_LINE;
  1663.             exit when not LINE_LIST.CURRENT_NEXT; -- adv to next line, check end
  1664.                                                   -- of list and exit if done
  1665.         end loop;
  1666.         if LINE_STOP /= LINE_LIST.LAST_INDEX then
  1667.             DUMMY := LINE_LIST.CURRENT_PREVIOUS; -- back up, for we have
  1668.                                                  -- gone too far
  1669.         end if;
  1670.     end COMMAND_LIST;
  1671.  
  1672. --===================================================================
  1673. -- Procedure COMMAND_DELETE
  1674. -- This procedure deletes lines over the range from LINE_START to LINE_STOP.
  1675. -- This range is a pair of global values which are set by RANGE_INPUT and
  1676. -- possibly by other routines.
  1677. -- 
  1678.     procedure COMMAND_DELETE is
  1679.         I     : NATURAL;
  1680.         DUMMY : BOOLEAN;
  1681.     begin
  1682.         COMMAND_GOTO (LINE_START); -- position to first line
  1683.         for I in 1 .. LINE_STOP - LINE_START + 1 loop
  1684.             LINE_LIST.DELETE_ELEMENT; -- delete current line
  1685.         end loop;
  1686.     end COMMAND_DELETE;
  1687.  
  1688. --===================================================================
  1689. -- COMMAND_SUBSTITUTE requires the following support routines, which are
  1690. -- contained within this functional area.
  1691. -- 
  1692. --      ROUTINE         FUNCTION
  1693. --      SUB_STRING      Determine if SUB_LINE is a substring of TARGET_LINE
  1694. --                        starting at position START_POS
  1695. --      COUNT_CHARS     Count the number of characters in the passed string,
  1696. --                        up to but not including the terminating ASCII.nul
  1697. --      SUBSTITUTE      Substitute NEW_STRING for OLD_STRING in TARGET_LINE
  1698. --                        starting at position FOUND_LOC (which is returned
  1699. -- 
  1700.  
  1701.  
  1702. -- 
  1703. -->> Function SUB_STRING
  1704. -- This function scans for the string SUB_LINE in the string TARGET_LINE
  1705. -- starting at the position START_POS.  Both strings are character sequences
  1706. -- terminated by ASCII.nul.  If found, SUB_STRING returns a positive number
  1707. -- which is the index in TARGET_LINE of the first character of the substring
  1708. -- SUB_LINE; the procedure SUBSTITUTE may be used to actually perform the
  1709. -- substitution, given this return value.  If not found, SUB_STRING returns
  1710. -- the number 0.
  1711. -- 
  1712.     function SUB_STRING (TARGET_LINE, SUB_LINE : LINE_STRING;
  1713.                          START_POS             : NATURAL) return NATURAL is
  1714.         FOUND_POS : NATURAL;
  1715.         TI, SI    : NATURAL;
  1716.         ANSWER    : BOOLEAN;
  1717.  
  1718.     begin
  1719. -- 
  1720. -- This initialization could have been done in the declarations above.
  1721. -- Old habits (from Pascal) are sometimes hard to break.
  1722. -- 
  1723.         TI := START_POS; -- set index in target line
  1724.         FOUND_POS := 0; -- initialize value to not found
  1725.         ANSWER := FALSE; -- ANSWER=TRUE if substring found
  1726. -- 
  1727. -- This is the major loop of SUB_STRING.  It advances through the TARGET_LINE
  1728. -- one character at a time, checking to see if SUB_LINE is duplicated in
  1729. -- TARGET_LINE starting at the current position.
  1730. -- 
  1731.         loop
  1732.             exit when TARGET_LINE (TI) = ASCII.NUL; -- done if at end of target
  1733. -- 
  1734. -- This is the minor loop of SUB_STRING.  It advances through SUB_LINE,
  1735. -- comparing each character in SUB_LINE to the corresponding (relative)
  1736. -- character in TARGET_LINE until either the end of SUB_LINE is reached
  1737. -- (in which case the substring has been found at TI, the current position
  1738. -- in TARGET_LINE) or the current character in SUB_LINE does not match
  1739. -- the current character in TARGET_LINE (in which case we advance to the
  1740. -- next character in TARGET_LINE and try again if the end of TARGET_LINE
  1741. -- has not been reached).
  1742. -- 
  1743.             for SI in 1 .. LINE_LENGTH loop
  1744.                 if SUB_LINE (SI) = ASCII.NUL then
  1745.                     -- exit if complete match
  1746.                     ANSWER := TRUE;
  1747.                     exit;
  1748.                 end if;
  1749.                 exit when TARGET_LINE (TI + SI - 1) /= SUB_LINE (SI);
  1750.             end loop;
  1751. -- 
  1752. -- We are now out of the preceeding FOR loop.  If ANSWER is TRUE, we got here
  1753. -- from the IF, which means we found a match.
  1754. -- 
  1755.             if ANSWER then
  1756.                 FOUND_POS := TI; -- mark position in target line and ...
  1757.                 exit;      -- ... exit major loop
  1758.             end if;
  1759. -- 
  1760. -- We have not matched the SUB_LINE yet; advance to the next character in
  1761. -- the TARGET_LINE.
  1762. -- 
  1763.             TI := TI + 1; -- advance to next char in target line
  1764.         end loop;
  1765. -- 
  1766. -- If the substring was found, FOUND_POS is non-zero.  If not, FOUND_POS
  1767. -- still retains its original value of zero.
  1768. -- 
  1769.         return (FOUND_POS);
  1770.  
  1771.     end SUB_STRING;
  1772.  
  1773. -- 
  1774. -->> Function COUNT_CHARS
  1775. -- The following function determines the number of characters in the
  1776. -- string (which is terminated by an ASCII.nul) passed to it.  This
  1777. -- character count does not include the terminating ASCII.nul.
  1778. -- 
  1779.     function COUNT_CHARS (STR : LINE_STRING) return NATURAL is
  1780.         I, J, K : NATURAL;
  1781.     begin
  1782.         J := LINE_LENGTH + 1;
  1783.         K := 0;
  1784.         for I in 1 .. J loop
  1785.             exit when STR (I) = ASCII.NUL;
  1786.             K := I;
  1787.         end loop;
  1788.         return (K); -- the loop exits on the ASCII.nul
  1789.     exception
  1790.         when others =>  -- must have exceeded dimension of STR
  1791.             return (LINE_LENGTH);
  1792.     end COUNT_CHARS;
  1793.  
  1794. -- 
  1795. -->> Procedure SUBSTITUTE
  1796. -- This procedure substitutes NEW_STRING for OLD_STRING in TARGET_LINE
  1797. -- starting at the position indicated by FOUND_LOC.  The value of FOUND_LOC
  1798. -- was determined by the routine SUB_STRING and is assumed to be correct
  1799. -- (ie, OLD_STRING starts at index FOUND_LOC in TARGET_LINE).
  1800. -- 
  1801.     procedure SUBSTITUTE (TARGET_LINE            : in out LINE_STRING;
  1802.                           OLD_STRING, NEW_STRING : LINE_STRING;
  1803.                           FOUND_LOC              : in out NATURAL) is
  1804.  
  1805.         SIZE_NEW, SIZE_OLD, SIZE_TARGET : NATURAL;
  1806.         I, NEXT_CHAR                    : NATURAL;
  1807.         RETURN_LOC                      : NATURAL;
  1808.         TEMP_LINE                       : LINE_STRING;
  1809.  
  1810. -- 
  1811. -- This is the mainline of SUBSTITUTE
  1812. -- 
  1813.     begin
  1814. -- 
  1815. -- Determine sizes of the three strings -- TARGET, OLD, and NEW
  1816. -- 
  1817.         SIZE_TARGET := COUNT_CHARS (TARGET_LINE);
  1818.         SIZE_OLD := COUNT_CHARS (OLD_STRING);
  1819.         SIZE_NEW := COUNT_CHARS (NEW_STRING);
  1820.  
  1821. -- 
  1822. -- Copy the TARGET_LINE up to but not including the point of substitution
  1823. -- 
  1824.         if FOUND_LOC /= 1 then
  1825.             TEMP_LINE (1 .. FOUND_LOC - 1) := TARGET_LINE (1 .. FOUND_LOC - 1);
  1826.             NEXT_CHAR := FOUND_LOC;
  1827.         else
  1828.             NEXT_CHAR := 1;
  1829.         end if;
  1830.  
  1831. -- 
  1832. -- Append the NEW_STRING to the end of the line being built
  1833. -- 
  1834.         if SIZE_NEW /= 0 then
  1835.             for I in 1 .. SIZE_NEW loop
  1836.                 TEMP_LINE (NEXT_CHAR) := NEW_STRING (I);
  1837.                 NEXT_CHAR := NEXT_CHAR + 1;
  1838.             end loop;
  1839.         end if;
  1840.  
  1841. -- 
  1842. -- Determine the index of the next character after the OLD_STRING in TARGET_LINE
  1843. -- 
  1844.         I := FOUND_LOC + SIZE_OLD;
  1845.  
  1846. -- 
  1847. -- Append the characters after OLD_STRING in TARGET_LINE to the end of the
  1848. -- line being built.
  1849. -- 
  1850.         loop
  1851.             exit when TARGET_LINE (I) = ASCII.NUL;
  1852.             TEMP_LINE (NEXT_CHAR) := TARGET_LINE (I);
  1853.             NEXT_CHAR := NEXT_CHAR + 1;
  1854.             I := I + 1;
  1855.         end loop;
  1856.  
  1857. -- 
  1858. -- Fill out the rest of the line which is being built with ASCII.nul chars
  1859. -- 
  1860.         for I in NEXT_CHAR .. LINE_LENGTH loop
  1861.             TEMP_LINE (I) := ASCII.NUL;
  1862.         end loop;
  1863.  
  1864. -- 
  1865. -- Replace the original TARGET_LINE with the line being built.
  1866. -- Also return the position to resume the scan in the TARGET_LINE in case
  1867. -- there is more than one occurrance of the substring.
  1868. -- 
  1869.         TARGET_LINE := TEMP_LINE;
  1870.         FOUND_LOC := FOUND_LOC + SIZE_NEW;
  1871.  
  1872.     end SUBSTITUTE;
  1873.  
  1874. --===================================================================
  1875. -- Procedure COMMAND_SUBSTITUTE
  1876. -- This procedure implements the Substitute command.  The range of lines
  1877. -- over which to perform the substitution is provided by RANGE_INPUT as
  1878. -- the global variables LINE_START and LINE_STOP, and the string OLD_STRING
  1879. -- contains the string to be substituted while the string NEW_STRING contains
  1880. -- the string to substitute for OLD_STRING.
  1881. -- 
  1882.     procedure COMMAND_SUBSTITUTE (OLD_STRING, NEW_STRING : LINE_STRING) is
  1883.         FOUND_LOC : NATURAL;
  1884.         TEMP_LINE : LINE_STRING;
  1885.     begin
  1886.         COMMAND_GOTO (LINE_START); -- goto first line in range
  1887.         FOUND_LOC := 1;     -- start at position 1 in first line
  1888.  
  1889. -- 
  1890. -- Major loop for substitution.  Each line is examined at least once, and,
  1891. -- if a substitution is performed, the line is passed over again to see
  1892. -- if the OLD_STRING occurrs in the line twice.
  1893. -- 
  1894.         loop
  1895.             exit when LINE_LIST.CURRENT_INDEX > LINE_STOP;
  1896. -- 
  1897. -- See if OLD_STRING is contained in the current line.
  1898. -- 
  1899.             FOUND_LOC := SUB_STRING
  1900.                             (LINE_LIST.RETURN_CURRENT_ELEMENT, OLD_STRING,
  1901.                              FOUND_LOC);
  1902. -- 
  1903. -- Replace OLD_STRING with NEW_STRING and look again after last character
  1904. -- in NEW_STRING within the current line if found; reset starting position
  1905. -- of search and advance to next line if not found.
  1906. -- 
  1907.             if FOUND_LOC /= 0 then
  1908.                 TEMP_LINE := LINE_LIST.RETURN_CURRENT_ELEMENT;
  1909.                 SUBSTITUTE (TEMP_LINE, OLD_STRING, NEW_STRING, FOUND_LOC);
  1910.                 LINE_LIST.RETURN_CURRENT_ELEMENT.CONTENT := TEMP_LINE;
  1911.                 PREFIX_PRINT (LINE_LIST.CURRENT_INDEX,
  1912.                               LINE_LIST.RETURN_CURRENT_ELEMENT);
  1913.                 NEW_LINE;
  1914.             else
  1915.                 FOUND_LOC := 1;
  1916.                 exit when not LINE_LIST.CURRENT_NEXT;
  1917.             end if;
  1918.  
  1919.         end loop;
  1920.  
  1921.     end COMMAND_SUBSTITUTE;
  1922.  
  1923. --===================================================================
  1924. -- Procedure COMMAND_FIND
  1925. -- This procedure implements the Find command.  It searches for the passed
  1926. -- string over a range of lines and stops at the first line in that range
  1927. -- which contains the indicated string.  LINE_START and LINE_STOP are
  1928. -- global values set by RANGE_INPUT which indicate the indexes of the first
  1929. -- and last lines in the range.
  1930. -- 
  1931. -- The routine SUB_STRING is used to determine if the passed string is
  1932. -- contained in the current line.
  1933. -- 
  1934.     procedure COMMAND_FIND (STR : LINE_STRING) is
  1935.         TEMP_LINE : LINE_STRING;
  1936.         I         : NATURAL;
  1937.     begin
  1938.         COMMAND_GOTO (LINE_START); -- position at first line
  1939. -- 
  1940. -- Exit when String is found, else advance to next line
  1941. -- 
  1942.         for I in LINE_START .. LINE_STOP loop
  1943.             TEMP_LINE := LINE_LIST.RETURN_CURRENT_ELEMENT;
  1944.             exit when SUB_STRING (TEMP_LINE, STR, 1) /= 0;
  1945.             exit when not LINE_LIST.CURRENT_NEXT; -- never hit this exit
  1946.         end loop;
  1947.     end COMMAND_FIND;
  1948.  
  1949. --===================================================================
  1950. -- File I/O Support Routines
  1951. -- 
  1952. -- This set of routines provides the basic support required to perform file
  1953. -- input/output with the editor.  These routines and their functions are:
  1954. -- 
  1955. -- ROUTINE              FUNCTION
  1956. -- WRITE_FLINE          Write the current line to the output file
  1957. -- PUT_RANGE            Write a group of lines to the output file
  1958. -- READ_FILE            Read a file into the edit buffer after the
  1959. --                        current line
  1960. -- 
  1961.  
  1962. -- 
  1963. -->> Procedure WRITE_FLINE
  1964. -- This procedure writes the current line out to the file whose descriptor
  1965. -- is passed as an argument.  The number of characters in the line is first
  1966. -- counted, and then TEXT_IO.PUT_LINE is used to write the line.
  1967. -- 
  1968.     procedure WRITE_FLINE (LOC_FILE : TEXT_IO.FILE_TYPE) is
  1969.         LEN : NATURAL;
  1970.     begin
  1971.         LEN := COUNT_CHARS (LINE_LIST.RETURN_CURRENT_ELEMENT);
  1972.         TEXT_IO.PUT_LINE (LOC_FILE,
  1973.                           LINE_LIST.RETURN_CURRENT_ELEMENT.CONTENT (1 .. LEN));
  1974.     end WRITE_FLINE;
  1975.  
  1976. -- 
  1977. -->> Procedure PUT_RANGE
  1978. -- PUT_RANGE positions to the first line, indexed by START, and writes lines
  1979. -- to the file via repeated calls to WRITE_FLINE until the line indexed by
  1980. -- STOP is written.
  1981. -- 
  1982.     procedure PUT_RANGE (FD : TEXT_IO.FILE_TYPE; START, STOP : NATURAL) is
  1983.         I : NATURAL;
  1984.     begin
  1985.         COMMAND_GOTO (START); -- position at first line
  1986.         for I in START .. STOP loop
  1987.             WRITE_FLINE (FD);           -- write current line
  1988.             exit when not LINE_LIST.CURRENT_NEXT; -- advance to next line
  1989.         end loop;
  1990.     end PUT_RANGE;
  1991.  
  1992. -- 
  1993. -->> Procedure READ_FILE
  1994. -- This procedure reads the file named by FILE_NAME into the edit buffer.
  1995. -- If the file is not found and CREATE_FLAG is TRUE, an empty file is
  1996. -- created; if the file is not found and CREATE_FLAG is FALSE, only an error
  1997. -- message is issued.
  1998. -- 
  1999.     procedure READ_FILE (FILE_NAME : STRING; CREATE_FLAG : BOOLEAN) is
  2000.         LOC_FILE : TEXT_IO.FILE_TYPE;
  2001.         INLINE   : LINE_STRING;
  2002.         LEN      : NATURAL;
  2003.  
  2004.     begin
  2005. -- 
  2006. -- Try to open the file for input.  If this fails because the file is not
  2007. -- found, the exception NAME_ERROR is raised.
  2008. -- 
  2009.         TEXT_IO.OPEN (LOC_FILE, TEXT_IO.IN_FILE, FILE_NAME);
  2010.  
  2011. -- 
  2012. -- Append lines after the current line until the end of the input file is
  2013. -- reached.
  2014. -- 
  2015.         loop
  2016.             exit when TEXT_IO.END_OF_FILE (LOC_FILE);
  2017.             TEXT_IO.GET_LINE (LOC_FILE, INLINE, LEN);
  2018.             for I in LEN + 1 .. LINE_LENGTH loop
  2019.                 INLINE (I) := ASCII.NUL;
  2020.             end loop;
  2021.             LINE_LIST.APPEND_ELEMENT (INLINE);
  2022.         end loop;
  2023.  
  2024. -- 
  2025. -- Close the Input File (generally, a good practice)
  2026. -- 
  2027.         TEXT_IO.CLOSE (LOC_FILE);
  2028.  
  2029. -- 
  2030. -- Handle problems; the big problem to look for is when the file is not
  2031. -- found (the exception NAME_ERROR is raised by TEXT_IO.OPEN).
  2032. -- 
  2033.     exception
  2034.  
  2035.         when TEXT_IO.NAME_ERROR => 
  2036. -- 
  2037. -- If the CREATE_FLAG is TRUE, create an empty file; else, say that file
  2038. -- was not found.
  2039. -- 
  2040.             if CREATE_FLAG then
  2041.                 TEXT_IO.CREATE (LOC_FILE, TEXT_IO.OUT_FILE, FILE_NAME);
  2042.                 TEXT_IO.CLOSE (LOC_FILE);
  2043.                 PUT ("New File");
  2044.                 NEW_LINE;
  2045.             else
  2046.                 PUT ("File not Found");
  2047.                 NEW_LINE;
  2048.             end if;
  2049.  
  2050.     end READ_FILE;
  2051.  
  2052.  
  2053. --===================================================================
  2054. -- Procedure COMMAND_GET
  2055. -- This procedure implements the Get command.  The file indicated by the
  2056. -- passed FILE_NAME is read into the edit buffer after the indicated line
  2057. -- (if any).
  2058. -- 
  2059.     procedure COMMAND_GET (FILE_NAME : LINE_STRING) is
  2060.         CURRENT_SAVE     : NATURAL;
  2061.         DUMMY            : BOOLEAN;
  2062.         FILE_NAME_LENGTH : NATURAL;
  2063.     begin
  2064.         FILE_NAME_LENGTH := FILE_NAME'LAST;
  2065.         for I in 1 .. FILE_NAME'LAST loop
  2066.             if FILE_NAME (I) = ASCII.NUL then
  2067.                 FILE_NAME_LENGTH := I - 1;
  2068.                 exit;
  2069.             end if;
  2070.         end loop;
  2071.         COMMAND_GOTO (LINE_START); -- position at indicated line
  2072.         CURRENT_SAVE := LINE_LIST.CURRENT_INDEX; -- save index of current line
  2073.         READ_FILE (FILE_NAME (1 .. FILE_NAME_LENGTH), FALSE); -- read file
  2074.         DUMMY := LINE_LIST.SET_CURRENT_INDEX (CURRENT_SAVE); -- restore current
  2075.     end COMMAND_GET;
  2076.  
  2077. --===================================================================
  2078. -- Procedure COMMAND_PUT
  2079. -- This procedure implements the Put command.  It writes out lines over
  2080. -- the range from LINE_START to LINE_STOP (input via RANGE_INPUT) to the file
  2081. -- named in the passed parameter.
  2082. -- 
  2083.     procedure COMMAND_PUT (FILE_NAME : LINE_STRING) is
  2084.         LOC_FILE         : TEXT_IO.FILE_TYPE;
  2085.         I                : NATURAL;
  2086.         FILE_NAME_LENGTH : NATURAL;
  2087.  
  2088.     begin
  2089. -- 
  2090. -- Compute length of file name
  2091. -- 
  2092.         FILE_NAME_LENGTH := FILE_NAME'LAST;
  2093.         for I in 1 .. FILE_NAME'LAST loop
  2094.             if FILE_NAME (I) = ASCII.NUL then
  2095.                 FILE_NAME_LENGTH := I - 1;
  2096.                 exit;
  2097.             end if;
  2098.         end loop;
  2099. -- 
  2100. -- Delete the original file, if any
  2101. -- 
  2102.         TEXT_IO.OPEN (LOC_FILE, TEXT_IO.IN_FILE,
  2103.                       FILE_NAME (1 .. FILE_NAME_LENGTH));
  2104.         TEXT_IO.DELETE (LOC_FILE);
  2105. -- 
  2106. -- Create the new file
  2107. -- 
  2108.         TEXT_IO.CREATE (LOC_FILE, TEXT_IO.OUT_FILE,
  2109.                         FILE_NAME (1 .. FILE_NAME_LENGTH));
  2110.         PUT_RANGE (LOC_FILE, LINE_START, LINE_STOP);
  2111.         TEXT_IO.CLOSE (LOC_FILE);
  2112. -- 
  2113. -- If the original file did not already exist, the above TEXT_IO.OPEN would
  2114. -- have raised the exception NAME_ERROR.  The following handler traps this
  2115. -- and goes ahead to create the file and write to it.
  2116. -- 
  2117.     exception
  2118.         when TEXT_IO.NAME_ERROR => 
  2119.             TEXT_IO.CREATE (LOC_FILE, TEXT_IO.OUT_FILE,
  2120.                             FILE_NAME (1 .. FILE_NAME_LENGTH));
  2121.             PUT_RANGE (LOC_FILE, LINE_START, LINE_STOP);
  2122.             TEXT_IO.CLOSE (LOC_FILE);
  2123.  
  2124.     end COMMAND_PUT;
  2125.  
  2126. --===================================================================
  2127.  
  2128. end EDIT_WORKER;
  2129.