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

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