1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  4    *                                                         *
  5    * Copyright (c) 1972 by Massachusetts Institute of        *
  6    * Technology and Honeywell Information Systems, Inc.      *
  7    *                                                         *
  8    *********************************************************** */
  9 
 10 
 11 /* Provides a canned answer when any question is asked during the execution of a command or request line */
 12 
 13 /* Created:  by THVV after R. Lamson */
 14 /* Rewritten: 20 March 1978 by G. Palter */
 15 /* Partially rewriten: 2 June 1978 by S.Herbst */
 16 /* Modified: July 1978 by J. C. Whitmore to use new command_query_info structure */
 17 /* Modified: 3 October 1979 by S. Herbst to fix usage message */
 18 /* Modified: 18 February 1980 by S. Herbst to add -call */
 19 /* Modified: 5 June 1981 by S. Herbst to add -match/-exclude and a warning for non-yes/no answer */
 20 /* Modified: 16 February 1982 by G. Palter to add ssu_answer_request_ and convert to a standalone invocation */
 21 /* Modified: 8 September 1982 by G. Palter to propogate subsystem/request line aborts */
 22 /* Modified: 27 March 1984 by S. Herbst to fix "Ignoring response FOO" message with -call */
 23 
 24 /* format: style4,delnl,insnl,ifthenstmt,ifthen */
 25 
 26 
 27 answer:
 28      procedure () options (variable);
 29 
 30 
 31 dcl  P_sci_ptr pointer parameter;                           /* ssu_answer_request_: -> SCI of the subsystem */
 32 dcl  P_info_ptr pointer parameter;                          /* ssu_answer_request_: -> subsystem's internal data */
 33 
 34 dcl  sci_ptr pointer;
 35 
 36 dcl  1 answer_node aligned based (answer_node_ptr),         /* holds one answer */
 37        2 query_sw bit (1),
 38        2 call_sw bit (1),
 39        2 call_ptr pointer,
 40        2 call_len fixed binary (21),
 41        2 times fixed binary,
 42        2 next_ptr pointer,
 43        2 answer_len fixed binary (21),
 44        2 answer character (arg_len refer (answer_node.answer_len));
 45 dcl  answer_node_ptr pointer;
 46 
 47 dcl  1 match_node aligned based (match_node_ptr),
 48        2 exclude_sw bit (1),
 49        2 regexp_sw bit (1),
 50        2 next_ptr pointer,
 51        2 match_len fixed binary (21),
 52        2 match_str character (arg_len refer (match_node.match_len)) unaligned;
 53 dcl  match_node_ptr pointer;
 54 
 55 %include cp_active_string_types;
 56 
 57 dcl  arg character (arg_len) based (arg_ptr) unaligned;
 58 dcl  based_answer character (answer_max_len) based;
 59 
 60 dcl  (arg_ptr, first_match_ptr, first_node_ptr, next_node_ptr, old_node_ptr, temp_ptr) pointer;
 61 
 62 dcl  area area based (area_ptr);
 63 dcl  area_ptr pointer;
 64 
 65 dcl  (standalone_invocation, brief_sw, call_opt_sw, found_first_answer, is_yes_or_no, yes_no) bit (1) aligned;
 66 
 67 dcl  (arg_count, arg_index, n) fixed binary;
 68 dcl  (answer_max_len, arg_len) fixed binary (21);
 69 dcl  code fixed binary (35);
 70 
 71 dcl  error_table_$bad_conversion fixed binary (35) external;
 72 dcl  error_table_$badopt fixed binary (35) external;
 73 dcl  ssu_et_$null_request_line fixed binary (35) external;
 74 dcl  ssu_et_$subsystem_aborted fixed binary (35) external;
 75 
 76 dcl  iox_$user_io pointer external;
 77 dcl  iox_$user_output pointer external;
 78 
 79 dcl  request_sw bit (1) aligned;
 80 dcl  request_line character (request_len) aligned based (request_ptr);
 81 dcl  request_ptr pointer;
 82 dcl  (request_len, request_start, start) fixed binary (21);
 83 
 84 dcl  com_err_ entry () options (variable);
 85 dcl  command_query_ entry () options (variable);
 86 dcl  condition_ entry (character (*), entry);
 87 dcl  cu_$arg_list_ptr entry () returns (pointer);
 88 dcl  cv_dec_check_ entry (character (*), fixed binary (35)) returns (fixed binary (35));
 89 dcl  get_system_free_area_ entry () returns (pointer);
 90 dcl  search_file_
 91           entry (pointer, fixed binary (21), fixed binary (21), pointer, fixed binary (21), fixed binary (21),
 92           fixed binary (21), fixed binary (21), fixed binary (35));
 93 dcl  ssu_$abort_line entry () options (variable);
 94 dcl  ssu_$abort_subsystem entry () options (variable);
 95 dcl  ssu_$arg_count entry (pointer, fixed binary);
 96 dcl  ssu_$arg_ptr entry (pointer, fixed binary, pointer, fixed binary (21));
 97 dcl  ssu_$destroy_invocation entry (pointer);
 98 dcl  ssu_$execute_line entry (pointer, pointer, fixed binary (21), fixed binary (35));
 99 dcl  ssu_$evaluate_active_string
100           entry (pointer, pointer, character (*), fixed binary, character (*) varying, fixed binary (35));
101 dcl  ssu_$get_subsystem_and_request_name entry (pointer) returns (character (72) varying);
102 dcl  ssu_$get_request_name entry (pointer) returns (character (32));
103 dcl  ssu_$get_temp_segment entry (pointer, character (*), pointer);
104 dcl  ssu_$print_message entry () options (variable);
105 dcl  ssu_$release_temp_segment entry (pointer, pointer);
106 dcl  ssu_$standalone_invocation entry (pointer, character (*), character (*), pointer, entry, fixed binary (35));
107 
108 dcl  (addr, binary, index, min, null, substr) builtin;
109 
110 dcl  (cleanup, command_question) condition;
111 %page;
112 %include query_info_;
113 %page;
114 %include condition_info_header;
115 %include command_question_info;
116 %page;
117 
118 /* Multics answer command */
119 
120 /* answer: entry () options (variable); */
121 
122           standalone_invocation = "1"b;                     /* must create a standalone subsystem to do this */
123           call ssu_$standalone_invocation (sci_ptr, "answer", "1.0", cu_$arg_list_ptr (), abort_answer_command, code);
124           if code ^= 0 then do;
125                call com_err_ (code, "answer", "Can not establish standalone subsystem invocation.");
126                return;
127           end;
128           go to COMMON;
129 
130 
131 /* Standard subsystem answer request */
132 
133 ssu_answer_request_:
134      entry (P_sci_ptr, P_info_ptr);
135 
136           standalone_invocation = "0"b;                     /* caller supplied the subsystem */
137           sci_ptr = P_sci_ptr;
138           go to COMMON;
139 
140 
141 /* Actual work starts here */
142 
143 COMMON:
144           area_ptr = get_system_free_area_ ();
145           answer_node_ptr, match_node_ptr, request_ptr, first_match_ptr, first_node_ptr, temp_ptr = null ();
146 
147           on condition (cleanup) call clean_up ();
148 
149           call ssu_$arg_count (sci_ptr, arg_count);
150           if arg_count = 0 then                             /* abort_line never returns */
151 USAGE:
152                call ssu_$abort_line (sci_ptr, 0, "Usage:  ^a string {-control_args} ^[command^;request^] line",
153                     ssu_$get_request_name (sci_ptr), standalone_invocation);
154 
155 
156           call ssu_$arg_ptr (sci_ptr, 1, arg_ptr, arg_len);
157 
158           call add_answer_node ();
159           first_node_ptr = answer_node_ptr;
160 
161           brief_sw, call_opt_sw = "0"b;
162           found_first_answer = ""b;                         /* this will be set when first answer is found */
163           request_sw = "0"b;
164           request_start = 0;
165           request_len = 0;
166 
167           do arg_index = 1 to arg_count;
168                call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
169                if ^request_sw then                          /* haven't begun imbedded request line yet */
170                     if substr (arg, 1, 1) = "-" then
171                          if arg = "-brief" | arg = "-bf" then brief_sw = "1"b;
172                                                             /* don't print question & answer */
173                          else if arg = "-times" then do;
174                               if ^found_first_answer then   /* this is only defined after some answer */
175 no_first:
176                                    call ssu_$abort_line (sci_ptr, 0, "First answer missing before ""^a"".", arg);
177                               arg_index = arg_index + 1;
178                               if arg_index > arg_count then
179 NO_CONTROL_VALUE:
180                                    call ssu_$abort_line (sci_ptr, 0, "No value specified for ""^a"".", arg);
181                               call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
182                               n = cv_dec_check_ (arg, code);
183                               if code ^= 0 then
184                                    call ssu_$abort_line (sci_ptr, error_table_$bad_conversion, "-times ""^a""", arg);
185                               answer_node.times = n;
186                          end;
187                          else if arg = "-call" then do;     /* expand active function to get answer */
188                               call_opt_sw = "1"b;
189                               arg_index = arg_index + 1;
190                               if arg_index > arg_count then go to NO_CONTROL_VALUE;
191                               call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
192                               if found_first_answer then
193                                    call add_answer_node ();
194                               else found_first_answer = "1"b;
195                               answer_node.call_sw = "1"b;
196                               answer_node.call_ptr = arg_ptr;
197                               answer_node.call_len = arg_len;
198                          end;
199                          else if arg = "-exclude" | arg = "-ex" then do;
200                               arg_index = arg_index + 1;
201                               if arg_index > arg_count then go to NO_CONTROL_VALUE;
202                               call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
203                               call add_match_node ();
204                               match_node.exclude_sw = "1"b;
205 MATCH_ARG:
206                               if substr (arg, 1, 1) = "/" & substr (arg, arg_len, 1) = "/" then do;
207                                    match_node.regexp_sw = "1"b;
208                                    match_node.match_len = arg_len - 2;
209                                    match_node.match_str = substr (arg, 2, arg_len - 2);
210                               end;
211                               else do;                      /* starname */
212                                    match_node.regexp_sw = "0"b;
213                                    match_node.match_str = arg;
214                               end;
215                          end;
216                          else if arg = "-match" then do;
217                               arg_index = arg_index + 1;
218                               if arg_index > arg_count then go to NO_CONTROL_VALUE;
219                               call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
220                               call add_match_node ();
221                               match_node.exclude_sw = "0"b;
222                               go to MATCH_ARG;
223                          end;
224                          else if arg = "-query" then do;
225                               if found_first_answer then    /* node is there for first answer */
226                                    call add_answer_node ();
227                               answer_node.query_sw = "1"b;
228                               found_first_answer = "1"b;    /* we have an answer now */
229                          end;
230                          else if arg = "-then" then do;
231                               if ^found_first_answer then go to no_first;
232                               arg_index = arg_index + 1;
233                               if arg_index > arg_count then go to NO_CONTROL_VALUE;
234                               call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
235                               call add_answer_node ();
236                               answer_node.answer = arg;
237                          end;
238                          else call ssu_$abort_line (sci_ptr, error_table_$badopt, """^a""", arg);
239                     else do;
240                          if ^found_first_answer then do;    /* this must be the first answer */
241                               answer_node.answer = arg;
242                               found_first_answer = "1"b;    /* say we got it */
243                          end;
244                          else do;                           /* otherwise this is the start of request line */
245                               request_sw = "1"b;            /* begin request line */
246                               request_start = arg_index;    /* remember where it started */
247                               request_len = arg_len + 1;    /* start computing length */
248                          end;
249                     end;
250 
251                else request_len = request_len + arg_len + 1;
252           end;
253 
254           if request_len = 0 then go to USAGE;
255           answer_node_ptr = first_node_ptr;
256 
257           if call_opt_sw then call ssu_$get_temp_segment (sci_ptr, "answer", temp_ptr);
258 
259           call condition_ ("command_question", answer_handler);
260                                                             /* setup handler */
261 
262           allocate request_line in (area) set (request_ptr);
263           request_line = "";
264 
265           start = 1;                                        /* build request line */
266           do arg_index = request_start to arg_count;
267                call ssu_$arg_ptr (sci_ptr, arg_index, arg_ptr, arg_len);
268                substr (request_line, start, arg_len) = arg;
269                start = start + arg_len + 1;
270           end;
271 
272           call ssu_$execute_line (sci_ptr, addr (request_line), start - 2, code);
273                                                             /* execute request line */
274           if ^standalone_invocation & (code ^= 0) & (code ^= ssu_et_$null_request_line) then
275                if code = ssu_et_$subsystem_aborted then
276                     call ssu_$abort_subsystem (sci_ptr);
277                else call ssu_$abort_line (sci_ptr);
278 
279 RETURN:
280           call clean_up ();
281 
282           return;
283 
284 
285 
286 /* Internal procedure invoked by ssu_$abort_line if answer was invoked as a Multics command (stanalone invocation) */
287 
288 abort_answer_command:
289      procedure ();
290 
291           go to RETURN;                                     /* message has been printed: now we can punt */
292 
293      end abort_answer_command;
294 
295 %page;
296 
297 /* This internal procedure supplies the answer when command_question is signalled.
298 */
299 
300 answer_handler:
301      procedure (mcptr, name, coptr, infoptr, continue_sw);
302 
303 dcl  (mcptr, coptr, infoptr) pointer parameter;
304 dcl  name character (*) parameter;
305 dcl  continue_sw bit (1) aligned parameter;
306 
307 %include query_info;
308 
309 dcl  1 as aligned based (inp),                              /* version 2 answer structure */
310        2 version fixed binary,                              /* ... always 2 */
311        2 status_code fixed binary (35),                     /* errorcode */
312        2 query_code fixed binary,
313        2 question_sw bit (1) unaligned,                     /* 1 to print question */
314        2 yes_or_no_sw bit (1) unaligned,                    /* 1 if must be yes/no */
315        2 preset_sw bit (1) unaligned,                       /* 1 if we answered */
316        2 answer_sw bit (1) unaligned,                       /* 1 if print answer */
317        2 np pointer,                                        /* ptr to asker name */
318        2 nl fixed binary,                                   /* len */
319        2 question_ptr pointer,                              /* ptr to question */
320        2 question_len fixed binary (21),                    /* len */
321        2 max_question_len fixed binary (21),
322        2 answer_ptr pointer,                                /* ptr to answer */
323        2 answer_len fixed binary (21),
324        2 max_answer_len fixed binary (21);
325 
326 declare  1 cqi aligned based (inp) like command_question_info;
327                                                             /* version 3 or 4 answer structure */
328 dcl  inp pointer;
329 
330 dcl  temp_answer character (4 * sys_info$max_seg_size - 4) varying based (temp_ptr);
331 dcl  sys_info$max_seg_size fixed binary (35) external;
332 dcl  question_string character (question_len) based (question_ptr);
333 dcl  buffer character (buffer_len) based (buffer_ptr);
334 dcl  (buffer_ptr, question_ptr) pointer;
335 dcl  buffer_len fixed binary (21);
336 dcl  question_len fixed binary (21);
337 dcl  length builtin;
338 
339           inp = infoptr;
340 
341           if as.version = 2 then do;
342                question_ptr = as.question_ptr;
343                question_len = as.question_len;
344           end;
345           else do;
346                question_ptr = cqi.question_ptr;
347                question_len = cqi.question_lth;
348           end;
349 
350           if first_match_ptr ^= null () then do;            /* some -match or -exclude args specified */
351                call process_selections (continue_sw, question_ptr, question_len);
352                if continue_sw then return;                  /* don't answer this question */
353           end;
354 
355           if answer_node_ptr = null ()                      /* have run out of answers */
356                | (as.version ^= 2 & cqi.version < 3)        /* unsupported answer structure */
357           then do;
358                continue_sw = "1"b;
359                return;
360           end;
361 
362           if answer_node.call_sw then do;                   /* answer -call ACTIVE_STRING */
363                buffer_ptr = answer_node.call_ptr;
364                buffer_len = answer_node.call_len;
365                on command_question system;
366                call ssu_$evaluate_active_string (sci_ptr, null (), buffer, NORMAL_ACTIVE_STRING, temp_answer, code);
367                if code ^= 0 then do;
368                     call ssu_$print_message (sci_ptr, code, "[^a]", buffer);
369                     query_info.suppress_name_sw = "1"b;
370                     if as.version = 2 then
371                          query_info.yes_or_no_sw = as.yes_or_no_sw;
372                     else query_info.yes_or_no_sw = cqi.yes_or_no_sw;
373 
374                     call command_query_ (addr (query_info), temp_answer, ssu_$get_subsystem_and_request_name (sci_ptr),
375                          "Please type answer to the following question:^/^a", question_string);
376                end;
377                revert command_question;
378                if as.version = 2 then
379                     yes_no = as.yes_or_no_sw;
380                else yes_no = cqi.yes_or_no_sw;
381                if temp_answer = "true" then temp_answer = "yes";
382                else if temp_answer = "false" then temp_answer = "no";
383                if temp_answer = "yes" | temp_answer = "y" | temp_answer = "no" | temp_answer = "n" then
384                     is_yes_or_no = "1"b;
385                else is_yes_or_no = "0"b;
386                answer_node.answer_len = length (temp_answer);
387                go to SET_ANSWER;
388           end;
389 
390           else if answer_node.query_sw then do;             /* -query */
391                if cqi.version >= 4 then do;                 /* iocbp's are defined in version 4 */
392                     cqi.question_iocbp = iox_$user_io;      /* ask question on user i/o */
393                     cqi.answer_iocbp = iox_$user_io;        /* and get answer from same place */
394                end;
395                continue_sw = "1"b;
396           end;
397 
398           else do;
399                if answer_node.answer = "yes" | answer_node.answer = "y" | answer_node.answer = "no"
400                     | answer_node.answer = "n" then
401                     is_yes_or_no = "1"b;
402                else is_yes_or_no = "0"b;
403 SET_ANSWER:
404                if as.version = 2 then do;                   /* old version structure */
405                     if as.yes_or_no_sw & ^is_yes_or_no then do;
406 REJECT_NON_YES_NO:
407                          if answer_node.call_sw then
408                               call ssu_$print_message (sci_ptr, 0,
409                                    "Ignoring response ""^a"" to yes-or-no question:^/^a",
410                                    temp_answer, question_string);
411                          else call ssu_$print_message (sci_ptr, 0,
412                                    "Ignoring response ""^a"" to yes-or-no question:^/^a",
413                                    answer_node.answer, question_string);
414                          continue_sw = "1"b;                /* continue to signal */
415                          return;
416                     end;
417                     answer_max_len = as.max_answer_len;
418                     as.answer_len = min (answer_max_len, answer_node.answer_len);
419                                                             /* careful of string lth */
420                     if answer_node.call_sw then
421                          substr (as.answer_ptr -> based_answer, 1, as.answer_len) = temp_answer;
422                     else substr (as.answer_ptr -> based_answer, 1, as.answer_len) = answer_node.answer;
423                     as.preset_sw = "1"b;                    /* preset answer given */
424                     as.question_sw, as.answer_sw = ^brief_sw;
425                end;                                         /* print if ^brief */
426 
427                else if cqi.version >= 3 then do;
428                     if cqi.yes_or_no_sw & ^is_yes_or_no then go to REJECT_NON_YES_NO;
429                     answer_max_len = cqi.max_answer_lth;
430                     cqi.answer_lth = min (answer_node.answer_len, answer_max_len);
431                                                             /* careful of string lth */
432                     if answer_node.call_sw then
433                          substr (cqi.answer_ptr -> based_answer, 1, cqi.answer_lth) = temp_answer;
434                     else substr (cqi.answer_ptr -> based_answer, 1, cqi.answer_lth) = answer_node.answer;
435                     cqi.preset_sw = "1"b;                   /* preset answer */
436                     cqi.question_sw, cqi.answer_sw = ^brief_sw;
437                     if cqi.version > 3 then                 /* if iocbp's are defined */
438                          cqi.question_iocbp = iox_$user_output;
439                end;                                         /* print question and answer on user_output */
440 
441                else do;                                     /* don't handle other versions */
442                     continue_sw = "1"b;
443                     return;
444                end;
445           end;
446 
447           answer_node.times = answer_node.times - 1;
448           if answer_node.times = 0 then answer_node_ptr = answer_node.next_ptr;
449 
450           return;
451 
452      end answer_handler;
453 %page;
454 add_answer_node:
455      procedure ();
456 
457           old_node_ptr = answer_node_ptr;
458 
459           allocate answer_node in (area) set (answer_node_ptr);
460 
461           answer_node.next_ptr = null ();                   /* this is the last node in the chain */
462 
463           if old_node_ptr ^= null () then do;               /* chain the nodes together */
464                old_node_ptr -> answer_node.next_ptr = answer_node_ptr;
465                if old_node_ptr -> answer_node.times = -1 then old_node_ptr -> answer_node.times = 1;
466                                                             /* if -times not given, assume 1 */
467           end;
468 
469           answer_node.query_sw = "0"b;
470           answer_node.call_sw = "0"b;
471           answer_node.times = -1;                           /* mark as not given yet */
472 
473      end add_answer_node;
474 
475 
476 
477 add_match_node:
478      procedure ();
479 
480           old_node_ptr = match_node_ptr;
481 
482           allocate match_node in (area) set (match_node_ptr);
483 
484           match_node.next_ptr = null ();                    /* this is the last node in the chain */
485 
486           if old_node_ptr ^= null () then                   /* thread onto last node */
487                old_node_ptr -> match_node.next_ptr = match_node_ptr;
488 
489           if first_match_ptr = null () then first_match_ptr = match_node_ptr;
490 
491      end add_match_node;
492 
493 
494 clean_up:
495      procedure ();
496 
497           if request_ptr ^= null () then free request_line in (area);
498 
499           if temp_ptr ^= null () then call ssu_$release_temp_segment (sci_ptr, temp_ptr);
500 
501           do answer_node_ptr = first_node_ptr repeat next_node_ptr while (answer_node_ptr ^= null ());
502                next_node_ptr = answer_node.next_ptr;
503                free answer_node in (area);
504           end;
505 
506           do match_node_ptr = first_match_ptr repeat next_node_ptr while (match_node_ptr ^= null ());
507                next_node_ptr = match_node.next_ptr;
508                free match_node in (area);
509           end;
510 
511           if standalone_invocation then                     /* we created the invocation for ourselves... */
512                call ssu_$destroy_invocation (sci_ptr);
513 
514      end clean_up;
515 %page;
516 process_selections:
517      procedure (P_continue_sw, P_question_ptr, P_question_len);
518 
519 dcl  P_continue_sw bit (1) aligned;                         /* ON = do not answer this question */
520 dcl  P_question_ptr pointer;
521 dcl  P_question_len fixed binary (21);
522 dcl  (match_node_ptr, mp) pointer;
523 
524           match_node_ptr = first_match_ptr;
525 
526           if match_node_ptr -> match_node.exclude_sw then
527                P_continue_sw = "0"b;                        /* excluding first: assume any question matches */
528           else P_continue_sw = "1"b;
529 
530           do mp = match_node_ptr repeat (mp -> match_node.next_ptr) while (mp ^= null ());
531                if mp -> match_node.exclude_sw then do;      /* exclude_sw if it matches */
532                     if ^P_continue_sw then                  /* only if still under consideration */
533                          if match_one (mp, P_question_ptr, P_question_len) then P_continue_sw = "1"b;
534                end;
535                else if P_continue_sw then                   /* -match: include only if already excluded */
536                     if match_one (mp, P_question_ptr, P_question_len) then P_continue_sw = "0"b;
537           end;
538 
539           return;
540 
541 
542 /* Returns "1"b if the question matches the given -match or -exclude string */
543 
544 match_one:
545           procedure (P_mp, P_ptr, P_len) returns (bit (1));
546 
547 dcl  P_mp pointer;                                          /* ptr to the next match node */
548 dcl  P_ptr pointer;                                         /* ptr to the question being considered */
549 dcl  P_len fixed binary (21);                               /* length of the question */
550 dcl  question_string character (P_len) based (P_ptr);
551 
552                if P_mp -> match_node.regexp_sw then
553                     call search_file_ (addr (P_mp -> match_node.match_str), 1, P_mp -> match_node.match_len, P_ptr, 1,
554                          P_len, 0, 0, code);
555 
556                else code = binary ((index (question_string, P_mp -> match_node.match_str) = 0), 35, 0);
557                                                             /* yields 1 if matches, 0 otherwise */
558 
559                return (code = 0);                           /* or vice-versa */
560 
561           end match_one;
562 
563      end process_selections;
564 
565      end answer;