1 
  2 /****^  HISTORY COMMENTS:
  3   1) change(2016-04-15,GDixon):
  4      Initial version of program to test input_history_ line edit requests.
  5                                                    END HISTORY COMMENTS */
  6 
  7           /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
  8           /*                                                                                                */
  9           /* Name:  ihtest                                                                                  */
 10           /*                                                                                                */
 11           /* Function: The input_history_ I/O module captures each input_line (read from user_input via     */
 12           /* iox_$get_line) in a per-user USER.history segment.  These input lines may later be selected    */
 13           /* via input line editor requests which input_history_ adds to the window_io_ real-time line      */
 14           /* editor.                                                                                        */
 15           /*                                                                                                */
 16           /* To debug input_history_, its normal function of providing input lines to the process collides  */
 17           /* with the need to provide input specifying debugging operations to perform.  Therefore,         */
 18           /* input_history_ is debugged mostly by adding debug ioa_ calls at strategic points in the code   */
 19           /* to trace its activities on user_output without requiring input from the user.                  */
 20           /*                                                                                                */
 21           /* However, when testing the requests which input_history_ adds to the window_io_ line editor,    */
 22           /* even this ioa_ tracing strategy fails because the trace output data interferes with            */
 23           /* presentation by the line editor of the input data being edited.                                */
 24           /*                                                                                                */
 25           /* ihtest avoids this problem by simulating the window_io_ line editor calls to particular        */
 26           /* input_history_ edit requests, so the requests may be tested without input_history_ actually    */
 27           /* being attached to window_io_.  This simulated environment is created as follows.               */
 28           /*                                                                                                */
 29           /* 1) ihtest tells input_history_ to fabricate its attach data structure (ihData), using a special*/
 30           /*    entrypoint in the I/O module: input_history_$validate_attach_options.                       */
 31           /*    Pointer to the returned ihData structure is then stored in input_history_'s iocb_dict       */
 32           /*    cache (associated with the iox_$user_io IOCB).                                              */
 33           /* 2) The window system in invoked, with window_io_ attached to the user_i/o switch.              */
 34           /* 3) Each simulated invocation of an input_history_ line editor request (e.g., ^P or ^N)         */
 35           /*    invokes the editing request, which uses and updates the simulated attach_data.              */
 36           /*                                                                                                */
 37           /* This scheme works because the window_io_ editor normally calls external edit requests by       */
 38           /* passing them a line_editor_info structure, which contains an iocb_ptr identifying the          */
 39           /* window_io_ instance  making the call (usually the user_i/o switch attached to the window_io_). */
 40           /* In the simulated test environment, ihtest creates its own line_editor_info structure, with a   */
 41           /* pointer to the user_i/o IOCB.  Each input_history_ edit request uses this iocb_ptr to find     */
 42           /* the simulated attach data in the input_history_ cache.                                         */
 43           /*                                                                                                */
 44           /*  - ihtest provides a -display operation to list the cached attach data structures.             */
 45           /*     - Calls input_history_$test_iocb_dict_display to do the work.                              */
 46           /*  - ihtest provides a -clear operation to remove the cached attach data structure.              */
 47           /*     - Calls input_history_$test_iocb_dict_clear to do the work.                                */
 48           /*                                                                                                */
 49           /* Operations:                                                                                    */
 50           /*    Several operations may be given in the same command, to simulate calls to same/different    */
 51           /*    edit routines during a single invocation of the window_io_ line editor.                     */
 52           /*                                                                                                */
 53           /*  -display        displays contents of the input_history_ iocb_dict cache.                      */
 54           /*  -clear          clears the user_i/o entry in the input_history_ iocb_dict cache.              */
 55           /*                  This simulates a new invocation of the window_io_ line editor, by resetting   */
 56           /*                  the input_history_ attach data.                                               */
 57           /*  -next, +nnn     invokes input_history_$ih_next_line for testing.  When the positive number    */
 58           /*                  form is used, nnn is the repetition count given in the line editor input      */
 59           /*                  when invoking the edit request (e.g., 3 or +3 invokes ih_next_line with a     */
 60           /*                  repetition count of 3).                                                       */
 61           /*  -previous, -nnn invokes input_history_$ih_previous_line for testing.  When the negative       */
 62           /*                  number form is used, nnn is the repetition count given in the line editor     */
 63           /*                  input when invoking the edit request (e.g., -5 invokes ih_previous_line with  */
 64           /*                  a repetition count of 5).                                                     */
 65           /*  -reverse_search, -reverse, -r                                                                 */
 66           /*                  invokes input_history_$ih_reverse_search for testing.  The user is then       */
 67           /*                  prompted for incremental search characters.                                   */
 68           /*  -search, -srch, -s                                                                            */
 69           /*                  invokes input_history_$ih_forward_search for testing.  The user is then       */
 70           /*                  prompted for incremental search characters.                                   */
 71           /*                                                                                                */
 72           /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
 73 %page;
 74 
 75 ihtest:
 76      proc options(variable);
 77 
 78   dcl  code fixed bin(35);
 79 
 80   dcl 1 lei aligned like line_editor_info;
 81   dcl  lei_buffer char(lei.line_length) based(addr(lei.input_buffer));
 82 
 83   dcl (FALSE init("0"b), TRUE init("1"b)) bit(1) aligned int static options(constant);
 84   dcl  NL char(1) int static options(constant) init("
 85 ");
 86   dcl  PROC char(6) int static options(constant) init("ihtest");
 87 
 88   dcl  com_err_ entry() options(variable);
 89   dcl  cu_$arg_count entry (fixed bin, fixed bin(35));
 90   dcl  cu_$arg_ptr entry (fixed bin, ptr, fixed bin(21), fixed bin(35));
 91   dcl  input_history_$ih_forward_search entry (ptr, fixed bin(35));
 92   dcl  input_history_$ih_next_line entry (ptr, fixed bin(35));
 93   dcl  input_history_$ih_previous_line entry (ptr, fixed bin(35));
 94   dcl  input_history_$ih_reverse_search entry (ptr, fixed bin(35));
 95   dcl  input_history_$test_iocb_dict_clear entry (ptr);
 96   dcl  input_history_$test_iocb_dict_display entry();
 97   dcl  input_history_$test_iocb_dict_get entry (ptr) returns(ptr);
 98   dcl  input_history_$validate_attach_options entry (char(*), char(*), (*) char(*) var, fixed bin(35));
 99   dcl  ioa_ entry() options(variable);
100   dcl (iox_$user_input, iox_$user_io) ptr ext static;
101 
102   dcl (error_table_$bad_opt,
103        error_table_$no_iocb,
104        video_et_$wsys_not_invoked
105                            ) fixed bin(35) ext static;
106 
107   dcl (addr, binary, null, substr, verify, unspec) builtin;
108 %page;
109           /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
110           /*                                                                                                */
111           /* Determine our function via the option parameter (if present).                                  */
112           /*                                                                                                */
113           /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
114 
115   dcl  operation char(40) var;
116   dcl  operationI fixed bin;
117   dcl  operationsN fixed bin;
118   dcl  optionP ptr, optionL fixed bin(21), option char(optionL) based(optionP);
119   dcl  repetitionCount fixed bin;
120 
121      call cu_$arg_count (operationsN, code);
122 
123 OPERATION_LOOP:
124      do operationI = 0 to operationsN;
125           repetitionCount = 1;
126 
127           if operationI = 0 then do;
128                if operationsN = 0 then go to PREVIOUS_LINE_REQ;
129                else go to NEXT_OPERATION;
130                end;
131 
132           call cu_$arg_ptr (operationI, optionP, optionL, code);
133           if option = "-clear" | option = "-c" then go to CLEAR_REQ;
134           if option = "-display" | option = "-disp" | option = "-d" then go to DISPLAY_REQ;
135           if option = "-next" | option = "-n" then go to NEXT_LINE_REQ;
136           if option = "-previous" | option = "-prev" | option = "-p" then go to PREVIOUS_LINE_REQ;
137           if option = "-reverse_search" | option = "-reverse" | option = "-rev" | option = "-r" then go to REVERSE_SEARCH_REQ;
138           if option = "-search" | option = "-srch" | option = "-s" then go to FORWARD_SEARCH_REQ;
139           if verify(option, "+-0123456789") = 0 then do;
140                repetitionCount = binary(option,17);
141                if repetitionCount < 0 then do;
142                     repetitionCount = -repetitionCount;
143                     go to PREVIOUS_LINE_REQ;
144                     end;
145                else if repetitionCount > 0 then go to NEXT_LINE_REQ;
146                end;
147           call com_err_ (error_table_$bad_opt, PROC, option);
148           return;
149 %page;
150 
151 PREVIOUS_LINE_REQ:
152           operation = "ih_previous_line";
153           call setup_request(operation, "^P" /* ^P */, repetitionCount, lei);
154           call input_history_$ih_previous_line (addr(lei), code);
155           go to END_REQUEST;
156 
157 NEXT_LINE_REQ:
158           operation = "ih_next_line";
159           call setup_request(operation, "^N" /* ^N */, repetitionCount, lei);
160           call input_history_$ih_next_line (addr(lei), code);
161           go to END_REQUEST;
162 
163 REVERSE_SEARCH_REQ:
164           operation = "ih_reverse_search";
165           call setup_request(operation, "^R" /* ^R */, repetitionCount, lei);
166           call input_history_$ih_reverse_search (addr(lei), code);
167           go to END_REQUEST;
168 
169 FORWARD_SEARCH_REQ:
170           operation = "ih_forward_search";
171           call setup_request(operation, "^S" /* ^S */, repetitionCount, lei);
172           call input_history_$ih_forward_search (addr(lei), code);
173           go to END_REQUEST;
174 
175 END_REQUEST:
176           if code ^= 0 then do;
177                if code = error_table_$no_iocb then do;
178                     call com_err_ (code, PROC, "lei.iocb_ptr: ^p (^a) not found in iocb_dict.",
179                          lei.iocb_ptr, lei.iocb_ptr->iocb.name);
180                     call input_history_$test_iocb_dict_display();
181                     end;
182                if code = video_et_$wsys_not_invoked then
183                     call com_err_ (code, PROC, "Must use 'wdc invoke' to test input_history_.");
184                return;                                      /* Stop loop if any error was reported.                   */
185                end;
186 
187           call ioa_ ("^a AFTER ^a [editor line: ^p (^d chars),   cursor index: ^d^[,   break: ^a^;^s^]]: ^a^12x'^a'",
188                NL, operation, addr(lei.input_buffer), lei.line_length, lei.cursor_index,
189                lei.break_given, interpret_break(lei.new_break_character), NL, lei_buffer);
190 
191 DISPLAY_REQ:
192           operation = "input_history_$test_iocb_dict_display";
193           call input_history_$test_iocb_dict_display();
194           go to NEXT_OPERATION;
195 
196 CLEAR_REQ:
197           operation = "input_history_$test_iocb_dict_clear";
198           ihDataP = input_history_$test_iocb_dict_get (iox_$user_io);
199           if ihDataP ^= null then do;
200                call input_history_$test_iocb_dict_clear (iox_$user_io);
201                free ihData in (ihArea);
202                end;
203 
204 NEXT_OPERATION:
205           call ioa_("");
206           end OPERATION_LOOP;
207      return;
208 
209 %page;
210 setup_request:
211      proc (op, keySeq, repetitionCount, lei);
212 
213   dcl  op char(40) var;                                     /* input_history_ operation being setup.                  */
214   dcl  keySeq char(4) var;                                  /* Key sequence assigned to edit request to be tested.(in)*/
215   dcl  repetitionCount fixed bin;                           /* Line editor repetitions for request to be tested. (in) */
216   dcl 1 lei aligned like line_editor_info;                  /* Line editor info passed to each request. (out)         */
217   dcl  lei_buffer char(lei.line_length) based(addr(lei.input_buffer));
218 
219           /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
220           /*                                                                                                */
221           /* For static testing (when input_history_ is not attached), need to:                             */
222           /*  - fabricate an ihData upon first call in the process.                                         */
223           /*  - store fabricated ihData in input_history_'s iocb_dict cache.                                */
224           /* Subsequent calls will re-use this ihData from the cache, until we clear our fabricated entry.  */
225           /*                                                                                                */
226           /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
227 
228   dcl  attach_options (1) char(20) var init("user_i/o");
229   dcl  code fixed bin(35);
230 
231      ihDataP = input_history_$test_iocb_dict_get (iox_$user_io);
232      if ihDataP = null then do;                             /* If ihtest called 1st time in this process, then...     */
233           call input_history_$validate_attach_options (PROC, "user_i/o", attach_options, code);
234                                                             /*  - Create, cache ihData structure.                     */
235           if code ^= 0 then return;                         /*     - If error, input_history_ reported it.            */
236           end;
237 
238      if lei.version ^= line_editor_info_version_3 then do;  /* Full initialization of lei structure?                  */
239           lei.version = line_editor_info_version_3;
240           lei.iocb_ptr = iox_$user_io -> iocb.actual_iocb_ptr;
241           unspec(lei.flags) = FALSE;
242           lei.flags.numarg_given = TRUE;
243           lei.flags.break_given = FALSE;
244           lei.user_data_ptr = null();
245           lei.cursor_index = 7;                             /* Starting edit buffer contents, which would come from   */
246           lei.line_length = 11;                             /*   window_io_ editor.  This simulates any input typed   */
247           lei.input_buffer = "CURSOR_here";                 /*   by user prior to using an input_history_ request.    */
248           lei.redisplay = redisplayBuffer;
249           lei.new_break_character = "";
250           lei.pad2 = "";
251           end;
252      lei.repetition_count = repetitionCount;
253      lei.key_sequence = keySeq;
254 
255      call ioa_ ("BEFORE ^a [editor line: ^p (^d chars),   cursor index: ^d]: ^a^12x'^a'",
256           op, addr(lei.input_buffer), lei.line_length, lei.cursor_index, NL, lei_buffer);
257 
258      end setup_request;
259 %page;
260 
261 interpret_break:                                            /* Return an interpreted description of                   */
262      proc (break) returns(char(16) var);                    /*  lei.new_break_character element upon return of the    */
263                                                             /*  editing function.                                     */
264   dcl  break char(1);
265 
266   /* Collate Char Constants */
267   dcl  AT  char(1) int static options(constant) init("@");
268   dcl  BEL char(1) int static options(constant) init("^G");
269   dcl  CTL char(1) int static options(constant) init("^");
270   dcl  DEL char(1) int static options(constant) init("^?");
271   dcl  HT  char(1) int static options(constant) init("      ");
272   dcl  NL  char(1) int static options(constant) init("
273 ");
274   dcl  NUL char(1) int static options(constant) init("^@");
275   dcl  PND char(1) int static options(constant) init("#");
276   dcl  SP  char(1) int static options(constant) init(" ");
277 
278      if break = NUL then return (CTL || AT);
279      if break < SP  then return (CTL || substr(collate(),(rank(break)+1+rank(AT)),1));
280      if break < DEL then return (substr(collate(),(rank(break)+1),1));
281      if break = DEL then return ("DEL");
282      if rank(break) < 256 then
283           return ("Meta-" || interpret_break(substr(collate(),(rank(break)+1-128),1)));
284      if rank(break) >= 256 then return ("BAD-" || ltrim(char(rank(break))));
285 
286      end interpret_break;
287 %page;
288 
289 redisplayBuffer:                                            /* Simulate actions of window_io_ redisplay_input_buffer  */
290      proc (leiP);                                           /*  by calling window_ to display lei.input_buffer on the */
291                                                             /*  current line of the default window.                   */
292                                                             /* NB: This method lacks special code in window_io_ to    */
293                                                             /*  properly interpret control characters, escape         */
294                                                             /*  sequences, etc (including HT locations).              */
295   dcl  leiP ptr;
296   dcl 1 lei aligned like line_editor_info based(leiP);
297   dcl  lei_buffer char(lei.line_length) based(addr(lei.input_buffer));
298 
299   dcl (cursorI, lineI) fixed bin;
300   dcl  ignoreCode fixed bin(35);
301 
302      call window_$get_cursor_position (lei.iocb_ptr, lineI, cursorI, code);
303      call window_$position_cursor (lei.iocb_ptr, lineI, 1, ignoreCode);
304      call window_$overwrite_text (lei.iocb_ptr, lei_buffer, ignoreCode);
305      call window_$clear_to_end_of_line (lei.iocb_ptr, ignoreCode);
306      call window_$position_cursor (lei.iocb_ptr, lineI, (lei.cursor_index), ignoreCode);
307      call window_$sync (lei.iocb_ptr, ignoreCode);
308 
309      end redisplayBuffer;
310 
311 %page;
312 %include input_history_data;
313 
314   dcl  ihArea area based(get_system_free_area_());          /* Area in which input_history_ attach data is allocated. */
315                                                             /* It is declared here, because it depends upon           */
316                                                             /* get_system_free_area_, which is declared in the        */
317                                                             /* window_io_attach_data_ include file.  This follows the */
318                                                             /* mechanism used within window_io_ for its allocations.  */
319   dcl  get_system_free_area_ entry() returns(ptr);
320 
321 %page;
322 %include iocb;
323 %page;
324 %include window_dcls;
325 %page;
326 %include window_line_editor;
327      end ihtest;