1 /***********************************************************************/
2 /* TARGET.C - Functions related to targets.                            */
3 /***********************************************************************/
4 /*
5  * THE - The Hessling Editor. A text editor similar to VM/CMS xedit.
6  * Copyright (C) 1991-2013 Mark Hessling
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to:
20  *
21  *    The Free Software Foundation, Inc.
22  *    675 Mass Ave,
23  *    Cambridge, MA 02139 USA.
24  *
25  *
26  * If you make modifications to this software that you feel increases
27  * it usefulness for the rest of the community, please email the
28  * changes, enhancements, bug fixes as well as any and all ideas to me.
29  * This software is going to be maintained and enhanced as deemed
30  * necessary by the community.
31  *
32  * Mark Hessling, mark@rexx.org  http://www.rexx.org/
33  */
34 
35 
36 #include <the.h>
37 #include <proto.h>
38 
39 #define STATE_START    0
40 #define STATE_DELIM    1
41 #define STATE_STRING   2
42 #define STATE_BOOLEAN  3
43 #define STATE_NEXT     4
44 #define STATE_POINT    5
45 #define STATE_ABSOLUTE 6
46 #define STATE_RELATIVE 7
47 #define STATE_POSITIVE 8
48 #define STATE_NEGATIVE 9
49 #define STATE_REGEXP_START   10
50 #define STATE_REGEXP   11
51 #define STATE_SPARE    12
52 #define STATE_QUIT     98
53 #define STATE_ERROR    99
54 
55 #ifdef HAVE_PROTO
56 static bool is_blank(LINE *);
57 #else
58 static bool is_blank();
59 #endif
60 
61 /***********************************************************************/
62 #ifdef HAVE_PROTO
target_type_match(CHARTYPE * ptr,CHARTYPE * type,int minlen)63 static int target_type_match( CHARTYPE *ptr, CHARTYPE *type, int minlen )
64 #else
65 static int target_type_match( ptr, type, minlen )
66 CHARTYPE *ptr, *type;
67 int minlen;
68 #endif
69 /***********************************************************************/
70 /*
71  * Return the length of ptr that matches from the minlen of type.
72  * e.g. chan, changed, 3 will result in 4
73  * If no match, return 0
74  */
75 {
76    int i, result=0, maxlen;
77 
78    TRACE_FUNCTION("target.c:  target_type_match");
79    maxlen = strlen( (DEFCHAR *)type );
80    for ( i = minlen; i <= maxlen; i++ )
81    {
82       if ( memcmpi( type, ptr, i ) == 0
83       && ( *(ptr+(i)) == ' '
84         || *(ptr+(i)) == '\0'
85         || *(ptr+(i)) == '\t') )
86       {
87          result = i;
88       }
89    }
90    TRACE_RETURN();
91    return result;
92 }
93 
94 /***********************************************************************/
95 #ifdef HAVE_PROTO
split_change_params(CHARTYPE * cmd_line,CHARTYPE ** old_str,CHARTYPE ** new_str,TARGET * target,LINETYPE * num,LINETYPE * occ)96 short split_change_params(CHARTYPE *cmd_line,CHARTYPE **old_str,CHARTYPE **new_str,
97                           TARGET *target,LINETYPE *num,LINETYPE *occ)
98 #else
99 short split_change_params(cmd_line,old_str,new_str,target,num,occ)
100 CHARTYPE *cmd_line,**old_str,**new_str;
101 TARGET *target;
102 LINETYPE *num,*occ;
103 #endif
104 /***********************************************************************/
105 {
106 #define SCP_PARAMS  2
107    CHARTYPE *word[SCP_PARAMS+1];
108    CHARTYPE strip[SCP_PARAMS];
109    LENGTHTYPE i=0,j=0;
110    CHARTYPE *target_start=NULL;
111    short rc=RC_OK;
112    CHARTYPE delim=' ';
113    LENGTHTYPE len=strlen((DEFCHAR *)cmd_line),idx=0;
114    long target_type = TARGET_NORMAL|TARGET_BLOCK_CURRENT|TARGET_ALL|TARGET_SPARE;
115    unsigned short num_params=0;
116    CHARTYPE _THE_FAR buffer[100];
117 
118    TRACE_FUNCTION("target.c:  split_change_params");
119    /*
120     * First, determine the delimiter; the first non-blank character in the argument
121     * string.
122     */
123    for ( i = 0; i < len; i++ )
124    {
125       if ( *(cmd_line+i ) != ' ' )
126       {
127          delim = *(cmd_line+i);
128          idx = i+1;
129          break;
130       }
131    }
132    /*
133     * Set up default values for the return values...
134     */
135    *old_str = cmd_line+idx;
136    *new_str = (CHARTYPE *)"";
137    target_start = (CHARTYPE *)"";
138    *num = *occ = 1L;
139    target->num_lines = 1L;
140    target->true_line = get_true_line(TRUE);
141    /*
142     * Set up default values for the return values...
143     */
144    for ( i = idx, j = 0; i < len; i++ )
145    {
146       if (*(cmd_line+i) == delim)
147       {
148          j++;
149          switch(j)
150          {
151             case 1:
152                *(cmd_line+i) = '\0';
153                *new_str = cmd_line+i+1;
154                break;
155             case 2:
156                *(cmd_line+i) = '\0';
157                target_start = cmd_line+i+1;
158                break;
159             default:
160                break;
161          }
162       }
163       if (j == 2)
164          break;
165    }
166    /*
167     * Check to see if there is a target, if not return here.
168     */
169    if (blank_field(target_start))
170    {
171       TRACE_RETURN();
172       return(RC_OK);
173    }
174    /*
175     * Parse and validate the target...
176     */
177    if ((rc = validate_target(target_start,target,target_type,get_true_line(TRUE),TRUE,TRUE)) != RC_OK)
178    {
179       TRACE_RETURN();
180       return(rc);
181    }
182    /*
183     * Check to see if there are further arguments after the target...
184     */
185    if (target->spare == (-1))
186    {
187       TRACE_RETURN();
188       return(RC_OK);
189    }
190    /*
191     * Validate the arguments following the target...
192     */
193    strip[0]=STRIP_BOTH;
194    strip[1]=STRIP_BOTH;
195    num_params = param_split(strtrunc(target->rt[target->spare].string),word,SCP_PARAMS,WORD_DELIMS,TEMP_PARAM,strip,FALSE);
196    if (num_params == 1
197    ||  num_params == 2)
198    {
199       if (strcmp((DEFCHAR *)word[0],"*") == 0)
200          *num = max_line_length;
201 /*       *num = MAX_LONG;*/
202       else
203       {
204          if ( ( rc = valid_positive_integer_against_maximum( word[0], MAX_WIDTH_NUM ) ) != 0 )
205          {
206          if ( rc == 4 )
207                sprintf( (DEFCHAR *)buffer, "%s", word[0] );
208             else
209                sprintf( (DEFCHAR *)buffer, "- MUST be <= %ld", MAX_WIDTH_NUM );
210             display_error( rc, buffer, FALSE );
211             TRACE_RETURN();
212             return(RC_INVALID_OPERAND);
213          }
214          else
215             *num = min(atol((DEFCHAR *)word[0]),max_line_length);
216       }
217    }
218    if (num_params == 2)
219    {
220       if ( ( rc = valid_positive_integer_against_maximum( word[1], MAX_WIDTH_NUM ) ) != 0 )
221       {
222          if ( rc == 4 )
223             sprintf( (DEFCHAR *)buffer, "%s", word[1] );
224          else
225             sprintf( (DEFCHAR *)buffer, "- MUST be <= %ld", MAX_WIDTH_NUM );
226          display_error( rc, buffer, FALSE );
227          TRACE_RETURN();
228          return(RC_INVALID_OPERAND);
229       }
230       else
231          *occ = atol((DEFCHAR *)word[1]);
232    }
233 
234    TRACE_RETURN();
235    return(RC_OK);
236 }
237 
238 /***********************************************************************/
239 #ifdef HAVE_PROTO
parse_target(CHARTYPE * target_spec,LINETYPE true_line,TARGET * target,long target_types,bool display_parse_error,bool allow_error_display,bool column_target)240 short parse_target(CHARTYPE *target_spec,LINETYPE true_line,TARGET *target,
241                    long target_types,bool display_parse_error,
242                    bool allow_error_display,bool column_target)
243 #else
244 short parse_target(target_spec,true_line,target,target_types,
245                    display_parse_error,allow_error_display,column_target)
246 CHARTYPE *target_spec;
247 LINETYPE true_line;
248 TARGET *target;
249 long target_types;
250 bool display_parse_error,allow_error_display,column_target;
251 #endif
252 /***********************************************************************/
253 {
254    short num_targets=0;
255    CHARTYPE boolean=' ';
256    short state=STATE_NEXT;
257    LENGTHTYPE len=0,inc=0,target_length=strlen((DEFCHAR *)target_spec),off=0;
258    CHARTYPE delim=' ';
259    LENGTHTYPE i=0;
260    LENGTHTYPE j=0;
261    LENGTHTYPE k=0;
262    LENGTHTYPE str_start=0,str_end=0;
263    short rc=RC_OK;
264    LENGTHTYPE potential_spare_start=0;
265    bool negative=FALSE;
266    CHARTYPE *ptr=NULL;
267    LINETYPE lineno=0L;
268    char regexp[7]="REGEXP";
269 
270    TRACE_FUNCTION("target.c:  parse_target");
271    /*
272     * Copy the incoming target specification...
273     */
274    if ((target->string = (CHARTYPE *)my_strdup(target_spec)) == NULL)
275    {
276       if (allow_error_display)
277          display_error(30,(CHARTYPE *)"",FALSE);
278       TRACE_RETURN();
279       return(RC_OUT_OF_MEMORY);
280    }
281    ptr = target->string;
282    /*
283     * Parse the target...
284     */
285    switch(target_types)
286    {
287       case TARGET_FIND:
288       case TARGET_NFIND:
289       case TARGET_FINDUP:
290       case TARGET_NFINDUP:
291          for (i=0;i<target_length;i++)
292          {
293             if (*(ptr+i) == ' ')
294                *(ptr+i) = CURRENT_VIEW->arbchar_single;
295             else
296                if (*(ptr+i) == '_')
297                   *(ptr+i) = ' ';
298          }
299          target->rt = (RTARGET *)(*the_malloc)(sizeof(RTARGET));
300          if (target->rt == NULL)
301          {
302             if (allow_error_display)
303                display_error(30,(CHARTYPE *)"",FALSE);
304             TRACE_RETURN();
305             return(RC_OUT_OF_MEMORY);
306          }
307          memset( target->rt, 0, sizeof(RTARGET) );
308          target->num_targets = 1;
309          target->rt[0].not_target = (target_types == TARGET_NFIND || target_types == TARGET_NFINDUP)?TRUE:FALSE;
310          target->rt[0].negative = (target_types == TARGET_FINDUP || target_types == TARGET_NFINDUP)?TRUE:FALSE;
311          target->rt[0].boolean = ' ';
312          target->rt[0].found = FALSE;
313          target->rt[0].length = target_length;
314          target->rt[0].target_type = TARGET_STRING;
315          target->rt[0].numeric_target = 0L;
316          target->rt[0].have_compiled_re = FALSE;
317          target->rt[0].string = (CHARTYPE *)(*the_malloc)((target_length*sizeof(CHARTYPE))+1);
318          if (target->rt[0].string == (CHARTYPE *)NULL)
319          {
320             if (allow_error_display)
321                display_error(30,(CHARTYPE *)"",FALSE);
322             TRACE_RETURN();
323             return(RC_OUT_OF_MEMORY);
324          }
325          strcpy((DEFCHAR *)target->rt[0].string,(DEFCHAR *)ptr);
326          TRACE_RETURN();
327          return(RC_OK);
328          break;
329       default:
330          break;
331    }
332    while(1)
333    {
334       inc = 1;
335       switch(state)
336       {
337          case STATE_NEXT:
338             if (target->rt == NULL)
339                target->rt = (RTARGET *)(*the_malloc)((num_targets+1)*sizeof(RTARGET));
340             else
341                target->rt = (RTARGET *)(*the_realloc)(target->rt,(num_targets+1)*sizeof(RTARGET));
342             if (target->rt == NULL)
343             {
344                if (allow_error_display)
345                   display_error(30,(CHARTYPE *)"",FALSE);
346                TRACE_RETURN();
347                return(RC_OUT_OF_MEMORY);
348             }
349             memset( &target->rt[num_targets], 0, sizeof(RTARGET) );
350             target->rt[num_targets].not_target = FALSE;
351             target->rt[num_targets].boolean = boolean;
352             target->rt[num_targets].found = FALSE;
353             target->rt[num_targets].length = 0;
354             target->rt[num_targets].string = NULL;
355             target->rt[num_targets].negative =  target->rt[0].negative; /* was FALSE; */
356             target->rt[num_targets].target_type = TARGET_ERR;
357             target->rt[num_targets].numeric_target = 0L;
358             target->rt[num_targets].have_compiled_re = FALSE;
359             if (target->spare != (-1))
360                state = STATE_SPARE;
361             else
362                state = STATE_START;
363             inc = 0;
364             break;
365          case STATE_START:
366             switch(*(ptr+i))
367             {
368                case '~': case '^':
369                   if (target->rt[num_targets].not_target)
370                   {
371                      state = STATE_ERROR;
372                      inc = 0;
373                      break;
374                   }
375                   target->rt[num_targets].not_target = TRUE;
376                   break;
377                case ' ':
378                case '\t':
379                   break;
380                case '-':
381                   target->rt[num_targets].negative = TRUE;
382                   state = STATE_NEGATIVE;
383                   break;
384                case 'r': case 'R':
385                   if (target->rt[num_targets].not_target
386                   ||  target->rt[num_targets].negative)
387                   {
388                      state = STATE_ERROR;
389                      inc = 0;
390                      break;
391                   }
392                   for ( k = 0; k < 6; k++ )
393                   {
394                      if ( i+k > target_length )
395                      {
396                         state = STATE_ERROR;
397                         break;
398                      }
399                      if ( toupper(*(ptr+i+k)) == regexp[k] )
400                         continue;
401                      else if ( *(ptr+(i+k)) == ' '
402                      ||   *(ptr+(i+k)) == '\0'
403                      ||   *(ptr+(i+k)) == '\t' )
404                      {
405                         state = STATE_REGEXP_START;
406                         break;
407                      }
408                      else
409                      {
410                         state = STATE_ERROR;
411                         break;
412                      }
413                   }
414                   switch( state )
415                   {
416                      case STATE_START:
417                         if ( *(ptr+(i+k)) == ' '
418                         ||   *(ptr+(i+k)) == '\0'
419                         ||   *(ptr+(i+k)) == '\t' )
420                         {
421                            state = STATE_REGEXP_START;
422                            inc = k;
423                            break;
424                         }
425                         else
426                         {
427                            state = STATE_ERROR;
428                            inc = 0;
429                            break;
430                         }
431                         break;
432                      case STATE_REGEXP_START:
433                         inc = k;
434                         break;
435                      default:
436                         state = STATE_ERROR;
437                         inc = 0;
438                         break;
439                   }
440                   potential_spare_start = i+k+1;
441                   break;
442                case '+':
443                   if (target->rt[num_targets].negative)
444                   {
445                      state = STATE_ERROR;
446                      inc = 0;
447                      break;
448                   }
449 /*                    inc = 1; */
450                   target->rt[num_targets].negative = FALSE;
451                   state = STATE_POSITIVE;
452                   break;
453                case '.':
454                   if (target->rt[num_targets].negative)
455                   {
456                      state = STATE_ERROR;
457                      inc = 0;
458                      break;
459                   }
460                   state = STATE_POINT;
461                   str_start = i;
462                   break;
463                case '*':
464                   state = STATE_BOOLEAN;
465                   target->rt[num_targets].target_type = TARGET_RELATIVE;
466                   target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(3);
467                   if (target->rt[num_targets].string == NULL)
468                   {
469                      if (allow_error_display)
470                         display_error(30,(CHARTYPE *)"",FALSE);
471                      TRACE_RETURN();
472                      return(RC_OUT_OF_MEMORY);
473                   }
474                   if (target->rt[num_targets].negative)
475                   {
476                      if (column_target)
477                         target->rt[num_targets].numeric_target = (LINETYPE)CURRENT_VIEW->zone_start - true_line - 1L;
478                      else
479                         target->rt[num_targets].numeric_target = true_line*(-1L);
480                      strcpy((DEFCHAR *)target->rt[num_targets].string,"-*");
481                   }
482                   else
483                   {
484                      if (column_target)
485                         target->rt[num_targets].numeric_target = (LINETYPE)((LINETYPE)CURRENT_VIEW->zone_end - true_line) + 1L;
486                      else
487                         target->rt[num_targets].numeric_target = (CURRENT_FILE->number_lines - true_line) + 2L;
488                      strcpy((DEFCHAR *)target->rt[num_targets].string,"*");
489                   }
490                   inc = 1;
491                   potential_spare_start = i+1;
492                   num_targets++;
493                   break;
494                case ':': case ';':
495                   state = STATE_ABSOLUTE;
496                   delim = *(ptr+i);
497                   str_start = i+1;
498                   break;
499                /* following are delimiters; make sure you change the other lists */
500                case '/': case '\\': case '@': case '`': case '#': case '$':
501                case '%': case '(': case ')': case '{': case '}': case '[': case ']':
502                case '"': case '\'': case '<': case '>': case ',': case 255:
503                   state = STATE_STRING;
504                   str_start = i+1;
505                   delim = *(ptr+i);
506                   break;
507                case 'a': case 'A':
508                   if (target->rt[num_targets].not_target
509                   ||  target->rt[num_targets].negative)
510                   {
511                      state = STATE_ERROR;
512                      inc = 0;
513                      break;
514                   }
515                   if (target_length-i < 3)
516                   {
517                      target->rt[num_targets].target_type = TARGET_ERR;
518                      state = STATE_ERROR;
519                      inc = 0;
520                      break;
521                   }
522                   /*
523                    * ALL target
524                    */
525                   inc = target_type_match( (CHARTYPE *)ptr+i, (CHARTYPE *)"all", 3 );
526                   if ( inc != 0 )
527                   {
528                      target->rt[num_targets].target_type = TARGET_ALL;
529                      state = STATE_BOOLEAN;
530                      num_targets++;
531                      potential_spare_start = i+inc;
532                      break;
533                   }
534                   /*
535                    * ALTERED target
536                    */
537                   inc = target_type_match( (CHARTYPE *)ptr+i, (CHARTYPE *)"altered", 3 );
538                   if ( inc != 0 )
539                   {
540                      target->rt[num_targets].target_type = TARGET_ALTERED;
541                      potential_spare_start = i+inc;
542                      state = STATE_BOOLEAN;
543                      num_targets++;
544                      break;
545                   }
546                   state = STATE_ERROR;
547                   inc = 0;
548                   break;
549                case 'b': case 'B':
550                   if (target_length-i < 5)
551                   {
552                      state = STATE_ERROR;
553                      inc = 0;
554                      break;
555                   }
556                   /*
557                    * BLANK target
558                    */
559                   inc = target_type_match( (CHARTYPE *)ptr+i, (CHARTYPE *)"blank", 5 );
560                   if ( inc != 0 )
561                   {
562                      target->rt[num_targets].target_type = TARGET_BLANK;
563                      potential_spare_start = i+inc;
564                      state = STATE_BOOLEAN;
565                      num_targets++;
566                      break;
567                   }
568                   /*
569                    * BLOCK target
570                    */
571                   if (memcmpi((CHARTYPE *)"block",ptr+i,5) == 0
572                   && (*(ptr+(i+5)) == ' '
573                       || *(ptr+(i+5)) == '\0'
574                       || *(ptr+(i+5)) == '\t'))
575                   {
576                      target->rt[num_targets].target_type = TARGET_BLOCK;
577                      inc = 5;
578                      potential_spare_start = i+5;
579                      state = STATE_BOOLEAN;
580                      num_targets++;
581                      break;
582                   }
583                   if (target->rt[num_targets].not_target
584                   ||  target->rt[num_targets].negative)
585                   {
586                      state = STATE_ERROR;
587                      inc = 0;
588                      break;
589                   }
590                   state = STATE_ERROR;
591                   inc = 0;
592                   break;
593                case 'n': case 'N':
594                   if (target_length-i < 3)
595                   {
596                      state = STATE_ERROR;
597                      inc = 0;
598                      break;
599                   }
600                   /*
601                    * NEW target
602                    */
603                   inc = target_type_match( (CHARTYPE *)ptr+i, (CHARTYPE *)"new", 3 );
604                   if ( inc != 0 )
605                   {
606                      target->rt[num_targets].target_type = TARGET_NEW;
607                      potential_spare_start = i+inc;
608                      state = STATE_BOOLEAN;
609                      num_targets++;
610                      break;
611                   }
612                   if (target->rt[num_targets].not_target
613                   ||  target->rt[num_targets].negative)
614                   {
615                      state = STATE_ERROR;
616                      inc = 0;
617                      break;
618                   }
619                   state = STATE_ERROR;
620                   inc = 0;
621                   break;
622                case 'c': case 'C':
623                   if (target_length-i < 3)
624                   {
625                      state = STATE_ERROR;
626                      inc = 0;
627                      break;
628                   }
629                   /*
630                    * CHANGED target
631                    */
632                   inc = target_type_match( (CHARTYPE *)ptr+i, (CHARTYPE *)"changed", 3 );
633                   if ( inc != 0 )
634                   {
635                      target->rt[num_targets].target_type = TARGET_CHANGED;
636                      potential_spare_start = i+inc;
637                      state = STATE_BOOLEAN;
638                      num_targets++;
639                      break;
640                   }
641                   if (target->rt[num_targets].not_target
642                   ||  target->rt[num_targets].negative)
643                   {
644                      state = STATE_ERROR;
645                      inc = 0;
646                      break;
647                   }
648                   state = STATE_ERROR;
649                   inc = 0;
650                   break;
651                case 't': case 'T':
652                   if (target_length-i < 3)
653                   {
654                      state = STATE_ERROR;
655                      inc = 0;
656                      break;
657                   }
658                   /*
659                    * TAGGED target
660                    */
661                   inc = target_type_match( (CHARTYPE *)ptr+i, (CHARTYPE *)"tagged", 3 );
662                   if ( inc != 0 )
663                   {
664                      target->rt[num_targets].target_type = TARGET_TAGGED;
665                      potential_spare_start = i+inc;
666                      state = STATE_BOOLEAN;
667                      num_targets++;
668                      break;
669                   }
670                   if (target->rt[num_targets].not_target
671                   ||  target->rt[num_targets].negative)
672                   {
673                      state = STATE_ERROR;
674                      inc = 0;
675                      break;
676                   }
677                   state = STATE_ERROR;
678                   inc = 0;
679                   break;
680                case '0': case '1': case '2': case '3': case '4':
681                case '5': case '6': case '7': case '8': case '9':
682                   if (UNTAAx)
683                      state = STATE_ABSOLUTE;
684                   else
685                      state = STATE_RELATIVE;
686                   str_start = i;
687                   delim = '\0';
688                   inc = 0;
689                   break;
690                default:
691                   state = STATE_ERROR;
692                   inc = 0;
693                   break;
694             }
695             break;
696          case STATE_REGEXP_START:
697             switch(*(ptr+i))
698             {
699                case ' ':
700                case '\t':
701                   break;
702                /* following are delimiters; make sure you change the other lists */
703                case '/': case '\\': case '@': case '`': case '#': case '$':
704                case '%': case '(': case ')': case '{': case '}': case '[': case ']':
705                case '"': case '\'': case '<': case '>': case ',': case 255:
706                   state = STATE_REGEXP;
707                   str_start = i+1;
708                   delim = *(ptr+i);
709                   break;
710                default:
711                   state = STATE_ERROR;
712                   inc = 0;
713                   break;
714             }
715             break;
716          case STATE_REGEXP:
717             switch(*(ptr+i))
718             {
719                /* following are delimiters; make sure you change the other lists */
720                case '/': case '\\': case '@': case '`': case '#': case '$':
721                case '%': case '(': case ')': case '{': case '}': case '[': case ']':
722                case '"': case '\'': case '<': case '>': case ',': case 255:
723                case '\0':
724                   if (*(ptr+i) == delim
725                   ||  *(ptr+i) == '\0')
726                   {
727                      state = STATE_BOOLEAN;
728                      str_end = i;
729                      len = str_end-str_start;
730                      target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
731                      if (target->rt[num_targets].string == NULL)
732                      {
733                         if (allow_error_display)
734                            display_error(30,(CHARTYPE *)"",FALSE);
735                         TRACE_RETURN();
736                         return(RC_OUT_OF_MEMORY);
737                      }
738                      memcpy(target->rt[num_targets].string,ptr+str_start,len);
739                      target->rt[num_targets].string[len] = '\0';
740                      target->rt[num_targets].target_type = TARGET_REGEXP;
741                      potential_spare_start = i+1;
742                      num_targets++;
743                   }
744                   break;
745                default:
746                   break;
747             }
748             break;
749          case STATE_STRING:
750             switch(*(ptr+i))
751             {
752                /* following are delimiters; make sure you change the other lists */
753                case '/': case '\\': case '@': case '`': case '#': case '$':
754                case '%': case '(': case ')': case '{': case '}': case '[': case ']':
755                case '"': case '\'': case '<': case '>': case ',': case 255:
756                case '\0':
757                   if (*(ptr+i) == delim
758                   ||  *(ptr+i) == '\0')
759                   {
760                      state = STATE_BOOLEAN;
761                      str_end = i;
762                      len = str_end-str_start;
763                      target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
764                      if (target->rt[num_targets].string == NULL)
765                      {
766                         if (allow_error_display)
767                            display_error(30,(CHARTYPE *)"",FALSE);
768                         TRACE_RETURN();
769                         return(RC_OUT_OF_MEMORY);
770                      }
771                      memcpy(target->rt[num_targets].string,ptr+str_start,len);
772                      target->rt[num_targets].string[len] = '\0';
773                      target->rt[num_targets].length = len;
774                      target->rt[num_targets].target_type = TARGET_STRING;
775                      potential_spare_start = i+1;
776                      num_targets++;
777                   }
778                   break;
779                default:
780                   break;
781             }
782             break;
783          case STATE_BOOLEAN:
784             switch(*(ptr+i))
785             {
786                case '\0':
787                   break;
788                case ' ':
789                case '\t':
790                   break;
791                case '&':
792                case '|':
793                   state = STATE_NEXT;
794                   boolean = *(ptr+i);
795                   break;
796                default:
797                   if (target_types & TARGET_SPARE)
798                   {
799 /*                       str_start = i;*/
800                      str_start = potential_spare_start;
801                      state = STATE_NEXT;
802                      target->spare = 0; /* just to ensure state is set */
803                      break;
804                   }
805                   state = STATE_ERROR;
806                   inc = 0;
807                   break;
808             }
809             break;
810          case STATE_SPARE:
811             switch(*(ptr+i))
812             {
813                case '\0':
814                   str_end = i;
815                   len = str_end-str_start;
816                   target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
817                   if (target->rt[num_targets].string == NULL)
818                   {
819                      if (allow_error_display)
820                         display_error(30,(CHARTYPE *)"",FALSE);
821                      TRACE_RETURN();
822                      return(RC_OUT_OF_MEMORY);
823                   }
824                   memcpy(target->rt[num_targets].string,ptr+str_start,len);
825                   target->rt[num_targets].string[len] = '\0';
826                   target->rt[num_targets].length = len;
827                   target->rt[num_targets].target_type = TARGET_SPARE;
828                   target->spare = num_targets;
829                   num_targets++;
830                   *(ptr+str_start) = '\0'; /* so target string does not include spare */
831                   break;
832                default:
833                   break;
834             }
835             break;
836          case STATE_ABSOLUTE:
837          case STATE_RELATIVE:
838             if (target->rt[num_targets].not_target)
839             {
840                state = STATE_ERROR;
841                inc = 0;
842                break;
843             }
844             switch(*(ptr+i))
845             {
846                case '\0':
847                case ' ':
848                case '\t':
849                   str_end = i;
850                   len = str_end-str_start;
851                   target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+2);
852                   if (target->rt[num_targets].string == NULL)
853                   {
854                      if (allow_error_display)
855                         display_error(30,(CHARTYPE *)"",FALSE);
856                      TRACE_RETURN();
857                      return(RC_OUT_OF_MEMORY);
858                   }
859                   if (delim != '\0')
860                   {
861                      target->rt[num_targets].string[0] = delim;
862                      off = 1;
863                   }
864                   else
865                      off = 0;
866                   memcpy(target->rt[num_targets].string+off,ptr+str_start,len);
867                   target->rt[num_targets].string[len+off] = '\0';
868                   target->rt[num_targets].length = len+off;
869                   target->rt[num_targets].target_type = (state == STATE_ABSOLUTE) ? TARGET_ABSOLUTE : TARGET_RELATIVE;
870                   target->rt[num_targets].numeric_target = atol((DEFCHAR *)target->rt[num_targets].string+off);
871                   if (target->rt[num_targets].negative)
872                      target->rt[num_targets].numeric_target *= (-1L);
873                   if (state == STATE_ABSOLUTE)
874                   {
875                      if (column_target)
876                      {
877 /*                          if (target->rt[num_targets].numeric_target < CURRENT_VIEW->current_column)*/
878                         if (target->rt[num_targets].numeric_target < true_line)
879                         {
880                            target->rt[num_targets].negative = TRUE;
881                            target->rt[num_targets].numeric_target = max(target->rt[num_targets].numeric_target,max(1,CURRENT_VIEW->zone_start-1));
882                         }
883                         else
884                            target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,min(max_line_length+1,CURRENT_VIEW->zone_end+1));
885                      }
886                      else
887                      {
888                         if (target->rt[num_targets].numeric_target < true_line)
889                            target->rt[num_targets].negative = TRUE;
890                         else
891                            target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,(CURRENT_FILE->number_lines+1L));
892                      }
893                   }
894                   else
895                   {
896                      if (column_target)
897                      {
898                         if (target->rt[num_targets].negative)
899                            target->rt[num_targets].numeric_target = max(target->rt[num_targets].numeric_target,((LINETYPE)CURRENT_VIEW->zone_start - true_line - 1L));
900                         else
901                            target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,((LINETYPE)CURRENT_VIEW->zone_end - true_line + 1L));
902                      }
903                      else
904                      {
905                         if (target->rt[num_targets].negative)
906                            target->rt[num_targets].numeric_target = max((target->rt[num_targets].numeric_target),(true_line == 0L) ? (0L) : (true_line*(-1L)));
907                         else
908                            target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,(CURRENT_FILE->number_lines - true_line+1L));
909                      }
910                   }
911                   potential_spare_start = i;
912                   num_targets++;
913                   state = STATE_BOOLEAN;
914                   break;
915                case '0': case '1': case '2': case '3': case '4':
916                case '5': case '6': case '7': case '8': case '9':
917                   break;
918                default:
919                   state = STATE_ERROR;
920                   inc = 0;
921                   break;
922             }
923             break;
924          case STATE_NEGATIVE:
925          case STATE_POSITIVE:
926             switch(*(ptr+i))
927             {
928                case '0': case '1': case '2': case '3': case '4':
929                case '5': case '6': case '7': case '8': case '9':
930                   state = STATE_RELATIVE;
931                   delim = (state==STATE_NEGATIVE) ? '-' : '+';
932                   str_start = i;
933                   inc = 0;
934                   break;
935                /* following are delimiters; make sure you change the other lists */
936                case '/': case '\\': case '@': case '`': case '#': case '$':
937                case '%': case '(': case ')': case '{': case '}': case '[': case ']':
938                case '"': case '\'': case '<': case '>': case ',': case 255:
939                case '\0':
940                   state = STATE_START;
941                   inc = 0;
942                   break;
943                case '*':
944                   state = STATE_START;
945                   inc = 0;
946                   break;
947                case 'b': case 'B':
948                case 'n': case 'N':
949                case 't': case 'T':
950                case 'c': case 'C':
951                case 'a': case 'A':
952                case 's': case 'S':
953                   /*
954                    * For -BLANK, -NEW, etc
955                    */
956                   state = STATE_START;
957                   inc = 0;
958                   break;
959                default:
960                   state = STATE_ERROR;
961                   inc = 0;
962                   break;
963             }
964             break;
965          case STATE_POINT:
966             switch(*(ptr+i))
967             {
968                case ' ':
969                case '\t':
970                   state = STATE_BOOLEAN;
971                   /* fall through */
972                case '&':
973                case '|':
974                case '\0':
975                   target->rt[num_targets].target_type = TARGET_POINT;
976                   str_end = i;
977                   len = str_end-str_start;
978                   target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
979                   if (target->rt[num_targets].string == NULL)
980                   {
981                      if (allow_error_display)
982                         display_error(30,(CHARTYPE *)"",FALSE);
983                      TRACE_RETURN();
984                      return(RC_OUT_OF_MEMORY);
985                   }
986                   memcpy(target->rt[num_targets].string,ptr+str_start,len);
987                   target->rt[num_targets].string[len] = '\0';
988                   target->rt[num_targets].length = len;
989                   if (find_named_line(target->rt[num_targets].string,&lineno,TRUE) == NULL)
990                   {
991                      if (allow_error_display)
992                         display_error(17,(CHARTYPE *)target->rt[num_targets].string,FALSE);
993                      TRACE_RETURN();
994                      return(RC_TARGET_NOT_FOUND);
995                   }
996                   target->rt[num_targets].numeric_target = lineno;
997                   if (target->rt[num_targets].numeric_target < true_line)
998                      target->rt[num_targets].negative = TRUE;
999                   else
1000                      target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,(CURRENT_FILE->number_lines+1L));
1001                   num_targets++;
1002                   potential_spare_start = i;
1003                   if (*(ptr+i) == ' ' || *(ptr+i) == '\t')
1004                      break;
1005                   boolean = *(ptr+i);
1006                   state = STATE_NEXT;
1007                   break;
1008                default:
1009                   break;
1010             }
1011             break;
1012          case STATE_ERROR:
1013             for (j=0;j<num_targets;j++)
1014                target->rt[j].target_type = TARGET_ERR;
1015             state = STATE_QUIT;
1016             break;
1017       }
1018       if (state == STATE_QUIT)
1019          break;
1020       i += inc;
1021       if (i > target_length) /* this allows for testing '\0' as delimiter */
1022          break;
1023    }
1024    target->num_targets = num_targets;
1025    if (num_targets == 0
1026    ||  target->rt[0].target_type == TARGET_ERR)
1027    {
1028       if (display_parse_error
1029       && allow_error_display)
1030          display_error(1,ptr,FALSE);
1031       TRACE_RETURN();
1032       return(RC_INVALID_OPERAND);
1033    }
1034    /*
1035     * Time to validate the targets we have parsed...
1036     *---------------------------------------------------------------------
1037     * Valid combinations are:
1038     * TARGET_ALL       (1 target only)
1039     *                  ALL  only
1040     * TARGET_BLOCK     (1 target only)
1041     *                 BLOCK  only
1042     *                  this section sets target_type to TARGET_BLOCK_ANY
1043     *                  or TARGET_BLOCK_CURRENT
1044     * TARGET_BLANK     (BLANK can be upper or lower case)
1045     *                  BLANK
1046     *                  -BLANK
1047     *                  ~BLANK
1048     *                  ~-BLANK
1049     * TARGET_NEW       (NEW can be upper or lower case)
1050     *                  NEW
1051     *                  -NEW
1052     *                  ~NEW
1053     *                  ~-NEW
1054     * TARGET_CHANGED   (CHANGED can be upper or lower case)
1055     *                  CHANGED
1056     *                  -CHANGED
1057     *                  ~CHANGED
1058     *                  ~-CHANGED
1059     * TARGET_TAGGED    (TAGGED can be upper or lower case)
1060     *                  TAGGED
1061     *                  -TAGGED
1062     *                  ~TAGGED
1063     *                  ~-TAGGED
1064     * TARGET_STRING    (various valid delimiters)
1065     *                  /string/
1066     *                  -/string/
1067     *                  ~/string/
1068     *                  ~-/string/
1069     * TARGET_POINT
1070     *                  .xxxxxx
1071     *                  ~.xxxxxx
1072     * TARGET_ABSOLUTE
1073     *                  :99
1074     *                  ;99
1075     * TARGET_RELATIVE
1076     *                  99
1077     *                  +99
1078     *                  -99
1079     *                  *
1080     *                  +*
1081     *                  -*
1082     * TARGET_REGEXP    (various valid delimiters)
1083     *                  /regexp/
1084     *
1085     * Any of the above target types may be or'd together.
1086     *---------------------------------------------------------------------
1087     * For each of the targets, check its validity...
1088     *---------------------------------------------------------------------
1089     */
1090    negative = target->rt[0].negative;
1091    for (i=0;i<num_targets-((target->spare == (-1)) ? 0 : 1);i++)
1092    {
1093       switch(target->rt[i].target_type)
1094       {
1095          case TARGET_BLOCK:
1096             if (num_targets-((target->spare == (-1)) ? 0 : 1) != 1)
1097             {
1098                rc = RC_INVALID_OPERAND;
1099                break;
1100             }
1101             if (target_types & TARGET_BLOCK_ANY)
1102                target->rt[i].target_type = TARGET_BLOCK_ANY;
1103             else
1104             {
1105                if (target_types & TARGET_BLOCK_CURRENT)
1106                   target->rt[i].target_type = TARGET_BLOCK_CURRENT;
1107                else
1108                   rc = RC_INVALID_OPERAND;
1109             }
1110             break;
1111          case TARGET_ALL:
1112             if (num_targets-((target->spare == (-1)) ? 0 : 1) != 1)
1113             {
1114                rc = RC_INVALID_OPERAND;
1115                break;
1116             }
1117             if (target_types & target->rt[i].target_type)
1118                break;
1119             rc = RC_INVALID_OPERAND;
1120             break;
1121          case TARGET_REGEXP:
1122             if (num_targets-((target->spare == (-1)) ? 0 : 1) != 1)
1123             {
1124                rc = RC_INVALID_OPERAND;
1125                break;
1126             }
1127             if ( !(target_types & target->rt[i].target_type) )
1128             {
1129                rc = RC_INVALID_OPERAND;
1130                break;
1131             }
1132             /*
1133              * Compile the RE
1134              */
1135             memset( &target->rt[i].pattern_buffer, 0, sizeof(struct re_pattern_buffer) );
1136             ptr = (CHARTYPE *)re_compile_pattern( (DEFCHAR *)target->rt[i].string, REGEXPx, strlen( (DEFCHAR *)target->rt[i].string ), &target->rt[i].pattern_buffer );
1137             if (ptr)
1138             {
1139                /*
1140                 * If ptr returns something, it is an error string
1141                 * Display it if we are allowed to...
1142                 */
1143                if ( display_parse_error
1144                &&   allow_error_display )
1145                {
1146                   sprintf( (DEFCHAR *)trec, "%s in %s", ptr, target->rt[i].string );
1147                   display_error( 216, (CHARTYPE *)trec, FALSE );
1148                   TRACE_RETURN();
1149                   return RC_INVALID_OPERAND;
1150                }
1151             }
1152             target->rt[i].have_compiled_re = TRUE;
1153             break;
1154          default:
1155             if (target->rt[i].negative != negative)
1156             {
1157                rc = RC_INVALID_OPERAND;
1158                break;
1159             }
1160             if (target_types & target->rt[i].target_type)
1161                break;
1162             rc = RC_INVALID_OPERAND;
1163             break;
1164       }
1165       if (rc == RC_INVALID_OPERAND)
1166          break;
1167    }
1168    /*
1169     * Display an error if anything found amiss and we are directed to
1170     * display an error...
1171     */
1172    if (rc != RC_OK
1173    && display_parse_error
1174    && allow_error_display)
1175       display_error( 1, ptr, FALSE );
1176    TRACE_RETURN();
1177    return(rc);
1178 }
1179 /***********************************************************************/
1180 #ifdef HAVE_PROTO
initialise_target(TARGET * target)1181 void initialise_target(TARGET *target)
1182 #else
1183 void initialise_target(target)
1184 TARGET *target;
1185 #endif
1186 /***********************************************************************/
1187 {
1188    TRACE_FUNCTION("target.c:  initialise_target");
1189    memset( target, 0, sizeof(TARGET) );
1190    target->spare = (-1);
1191    TRACE_RETURN();
1192    return;
1193 }
1194 /***********************************************************************/
1195 #ifdef HAVE_PROTO
free_target(TARGET * target)1196 void free_target(TARGET *target)
1197 #else
1198 void free_target(target)
1199 TARGET *target;
1200 #endif
1201 /***********************************************************************/
1202 {
1203    register short i=0;
1204 
1205    TRACE_FUNCTION("target.c:  free_target");
1206    if (target->string == NULL
1207    &&  target->num_targets == 0
1208    &&  target->rt == NULL)
1209    {
1210       TRACE_RETURN();
1211       return;
1212    }
1213    for (i=0;i<target->num_targets;i++)
1214    {
1215       if (target->rt[i].string != NULL)
1216          (*the_free)(target->rt[i].string);
1217       if (target->rt[i].have_compiled_re)
1218          the_regfree(&target->rt[i].pattern_buffer);
1219    }
1220    if (target->string != NULL)
1221       (*the_free)(target->string);
1222    if (target->rt != NULL)
1223       (*the_free)(target->rt);
1224    target->string = NULL;
1225    target->num_targets = 0;
1226    target->rt = NULL;
1227    TRACE_RETURN();
1228    return;
1229 }
1230 /***********************************************************************/
1231 #ifdef HAVE_PROTO
find_target(TARGET * target,LINETYPE true_line,bool display_parse_error,bool allow_error_display)1232 short find_target( TARGET *target, LINETYPE true_line, bool display_parse_error, bool allow_error_display )
1233 #else
1234 short find_target( target, true_line, display_parse_error, allow_error_display )
1235 TARGET *target;
1236 LINETYPE true_line;
1237 bool display_parse_error, allow_error_display;
1238 #endif
1239 /***********************************************************************/
1240 {
1241    short rc=RC_OK;
1242    LINE *curr=NULL;
1243    LINE tmpcurr;
1244    LINETYPE num_lines=0L;
1245    LINETYPE line_number=0L;
1246    LENGTHTYPE first_found_column=0;
1247    short status=RC_OK;
1248    int i;
1249 
1250    TRACE_FUNCTION( "target.c:  find_target" );
1251    /*
1252     * Check single targets first (ALL and BLOCK)
1253     *---------------------------------------------------------------------
1254     * Check if first, and only target, is BLOCK...
1255     */
1256    switch( target->rt[0].target_type )
1257    {
1258       case TARGET_ALL:
1259          target->true_line = 1L;
1260          target->last_line = CURRENT_FILE->number_lines;
1261          target->num_lines = CURRENT_FILE->number_lines;
1262          TRACE_RETURN();
1263          return(RC_OK);
1264          break;
1265       case TARGET_BLOCK_ANY:
1266          if ( MARK_VIEW == NULL )
1267          {
1268             if ( allow_error_display )
1269                display_error( 44, (CHARTYPE *)"", FALSE );
1270             rc = RC_TARGET_NOT_FOUND;
1271          }
1272          else
1273          {
1274             target->num_lines = MARK_VIEW->mark_end_line - MARK_VIEW->mark_start_line + 1L;
1275             target->true_line = MARK_VIEW->mark_start_line;
1276             target->last_line = MARK_VIEW->mark_end_line;
1277          }
1278          TRACE_RETURN();
1279          return rc;
1280          break;
1281       case TARGET_BLOCK_CURRENT:
1282          if ( MARK_VIEW == NULL )
1283          {
1284             if ( allow_error_display )
1285                display_error( 44, (CHARTYPE *)"", FALSE );
1286             rc = RC_TARGET_NOT_FOUND;
1287          }
1288          else
1289          {
1290             if ( MARK_VIEW != CURRENT_VIEW )
1291             {
1292                if ( allow_error_display )
1293                   display_error( 45, (CHARTYPE *)"", FALSE );
1294                rc = RC_TARGET_NOT_FOUND;
1295             }
1296             else
1297             {
1298                /*
1299                 * CUA blocks can have end_line < start_line
1300                 */
1301                if ( MARK_VIEW->mark_type == M_CUA
1302                &&   MARK_VIEW->mark_end_line < MARK_VIEW->mark_start_line )
1303                {
1304                   target->num_lines = MARK_VIEW->mark_start_line - MARK_VIEW->mark_end_line + 1L;
1305                   target->true_line = MARK_VIEW->mark_start_line;
1306                   target->last_line = MARK_VIEW->mark_end_line;
1307                }
1308                else
1309                {
1310                   target->num_lines = MARK_VIEW->mark_end_line - MARK_VIEW->mark_start_line + 1L;
1311                   target->true_line = MARK_VIEW->mark_start_line;
1312                   target->last_line = MARK_VIEW->mark_end_line;
1313                }
1314             }
1315          }
1316          TRACE_RETURN();
1317          return rc;
1318          break;
1319       default:
1320          break;
1321    }
1322    /*
1323     * All other targets are potentially repeating targets...
1324     */
1325    rc = RC_TARGET_NOT_FOUND;
1326    line_number = true_line;
1327    /*
1328     * Find the focus line
1329     */
1330    curr = lll_find( CURRENT_FILE->first_line, CURRENT_FILE->last_line, true_line, CURRENT_FILE->number_lines );
1331    /*
1332     * If this is a search and we are on the focus line use the current
1333     * working data, so make up a dummy LINE.
1334     */
1335    if ( target->search_semantics
1336    &&   CURRENT_VIEW->current_window == WINDOW_FILEAREA )
1337    {
1338       memset( &tmpcurr, 0, sizeof(LINE) );
1339       tmpcurr.line = rec;
1340       tmpcurr.length = rec_len;
1341       tmpcurr.next = curr->next;
1342       tmpcurr.prev = curr->prev;
1343       curr = &tmpcurr;
1344    }
1345    num_lines = 0L;
1346    for ( ; ; )
1347    {
1348       /*
1349        * For all repeating targets, see if the combined targets are
1350        * found on the line we are currently processing
1351        */
1352       status = find_rtarget_target( curr, target, true_line, line_number, &num_lines );
1353       if ( status != RC_TARGET_NOT_FOUND )
1354          break;
1355       /*
1356        * We can determine the direction of execution based on the first
1357        * target, as all targets must have the same direction to have reached
1358        * here.
1359        */
1360       if ( target->rt[0].negative )
1361       {
1362          /*
1363           * We didn't find the combined targets on this line, so get the previous line
1364           */
1365          curr = curr->prev;
1366          line_number--;
1367          if ( curr )
1368          {
1369             /*
1370              * We have a real line, so set the target focus_column to
1371              * after the end of the line (if SEARCHing) or to the start
1372              * of the line (if LOCATEing)
1373              * When setting "after the end of line", we have to take into
1374              * consideration the length of the needle, in case it ends in space
1375              * (we need to be able to find a string with a trailing space).
1376              */
1377             if ( target->search_semantics )
1378                target->focus_column = curr->length+1;
1379             else
1380                target->focus_column = 0;
1381          }
1382       }
1383       else
1384       {
1385          /*
1386           * Get the next line if locating/searching forward
1387           */
1388          curr = curr->next;
1389          line_number++;
1390       }
1391       if (curr == NULL)
1392          break;
1393    }
1394    if (status == RC_OK)
1395    {
1396       num_lines = ((target->rt[0].negative) ? -num_lines : num_lines);
1397       target->num_lines = num_lines;
1398       target->true_line = true_line;
1399       if (target->rt[0].negative)
1400       {
1401          curr = curr->next;
1402          target->last_line = find_next_in_scope(CURRENT_VIEW,curr,++line_number,DIRECTION_FORWARD);
1403       }
1404       else
1405       {
1406          curr = curr->prev;
1407          target->last_line = find_next_in_scope(CURRENT_VIEW,curr,--line_number,DIRECTION_BACKWARD);
1408       }
1409       /*
1410        * We found at least one of our potential targets.
1411        * When SEARCHing, we need to know where to move the cursor. We
1412        * find the lowest column of the targets that have been found
1413        * and set target->focus_column to that column.
1414        */
1415       if ( target->search_semantics )
1416       {
1417          for ( i = 0; i < target->num_targets ; i++ )
1418          {
1419             if ( target->rt[i].found )
1420             {
1421                if ( first_found_column == 0 )
1422                   first_found_column = target->rt[i].start;
1423                else if ( target->rt[i].start < first_found_column )
1424                   first_found_column = target->rt[i].start;
1425             }
1426          }
1427          target->focus_column = first_found_column;
1428       }
1429       rc = RC_OK;
1430    }
1431    else if (status == RC_TARGET_NOT_FOUND)
1432    {
1433       if (allow_error_display)
1434          display_error(17,target->string,FALSE);
1435       rc = RC_TARGET_NOT_FOUND;
1436    }
1437    else
1438       rc = status;
1439    TRACE_RETURN();
1440    return(rc);
1441 }
1442 /***********************************************************************/
1443 #ifdef HAVE_PROTO
find_column_target(CHARTYPE * line,LENGTHTYPE len,TARGET * target,LENGTHTYPE true_column,bool display_parse_error,bool allow_error_display)1444 short find_column_target(CHARTYPE *line,LENGTHTYPE len,TARGET *target,LENGTHTYPE true_column,bool display_parse_error,bool allow_error_display)
1445 #else
1446 short find_column_target(line,len,target,true_column,display_parse_error,allow_error_display)
1447 CHARTYPE *line;
1448 LENGTHTYPE len;
1449 TARGET *target;
1450 LENGTHTYPE true_column;
1451 bool display_parse_error,allow_error_display;
1452 #endif
1453 /***********************************************************************/
1454 {
1455    short rc=RC_OK;
1456    LENGTHTYPE column_number=0L;
1457    LENGTHTYPE num_columns=0L;
1458    bool status=FALSE;
1459 
1460    TRACE_FUNCTION("target.c:  find_column_target");
1461    /*
1462     * All column targets are potentially repeating targets...
1463     */
1464    rc = RC_TARGET_NOT_FOUND;
1465    status = FALSE;
1466    column_number = true_column;
1467    num_columns = 0;
1468    while(1)
1469    {
1470       status = find_rtarget_column_target(line,len,target,true_column,column_number,&num_columns);
1471       if (status)
1472          break;
1473       /*
1474        * We can determine the direction of execution based on the first
1475        * target, as all targets must have the same direction to have reached
1476        * here.
1477        */
1478       if (target->rt[0].negative)
1479       {
1480          if (column_number-- == (LINETYPE)CURRENT_VIEW->zone_start - 2L)
1481          {
1482             status = FALSE;
1483             break;
1484          }
1485       }
1486       else
1487       {
1488          if (column_number++ == (LINETYPE)CURRENT_VIEW->zone_end + 2L)
1489          {
1490             status = FALSE;
1491             break;
1492          }
1493       }
1494    }
1495    if (status)
1496    {
1497       num_columns = ((target->rt[0].negative) ? -num_columns : num_columns);
1498       target->num_lines = num_columns;
1499       target->true_line = (LINETYPE)true_column;
1500       target->last_line = (LINETYPE)column_number;
1501       rc = RC_OK;
1502    }
1503    else
1504    {
1505       if (allow_error_display)
1506          display_error(17,target->string,FALSE);
1507       rc = RC_TARGET_NOT_FOUND;
1508    }
1509    TRACE_RETURN();
1510    return(rc);
1511 }
1512 /***********************************************************************/
1513 #ifdef HAVE_PROTO
is_blank(LINE * curr)1514 static bool is_blank(LINE *curr)
1515 #else
1516 static bool is_blank(curr)
1517 LINE *curr;
1518 #endif
1519 /***********************************************************************/
1520 {
1521    LENGTHTYPE i=0;
1522    bool rc=TRUE;
1523 
1524    TRACE_FUNCTION("target.c:  is_blank");
1525    if (CURRENT_VIEW->zone_start > curr->length)
1526    {
1527       TRACE_RETURN();
1528       return(TRUE);
1529    }
1530    for (i=CURRENT_VIEW->zone_start-1;i<min(CURRENT_VIEW->zone_end,curr->length);i++)
1531    {
1532       if (*(curr->line+i) != ' ')
1533       {
1534          rc = FALSE;
1535          break;
1536       }
1537    }
1538    TRACE_RETURN();
1539    return(rc);
1540 }
1541 /***********************************************************************/
1542 #ifdef HAVE_PROTO
find_line_name(LINE * curr,CHARTYPE * name)1543 THELIST *find_line_name( LINE *curr, CHARTYPE *name )
1544 #else
1545 THELIST *find_line_name( curr, name )
1546 LINE *curr;
1547 CHARTYPE *name;
1548 #endif
1549 /***********************************************************************/
1550 /*
1551  * Given a pointer to a LINE, find the passed name and return a pointer to the
1552  * generic THELIST item if the name is in the list of names.
1553  */
1554 {
1555    THELIST *list_curr=NULL;
1556 
1557    TRACE_FUNCTION("target.c:  find_line_name");
1558    if ( curr == NULL
1559    ||   curr->first_name == NULL )
1560    {
1561       TRACE_RETURN();
1562       return( (THELIST *)NULL );
1563    }
1564    /*
1565     * Look for the passed in name...
1566     */
1567    list_curr = curr->first_name;
1568    while( list_curr != NULL )
1569    {
1570       if ( strcmp( (DEFCHAR *)list_curr->data, (DEFCHAR *)name ) == 0 )
1571       {
1572          TRACE_RETURN();
1573          return( list_curr );
1574       }
1575       list_curr = list_curr->next;
1576    }
1577    TRACE_RETURN();
1578    return( (THELIST *)NULL );
1579 }
1580 /***********************************************************************/
1581 #ifdef HAVE_PROTO
find_named_line(CHARTYPE * name,LINETYPE * retline,bool respect_scope)1582 LINE *find_named_line(CHARTYPE *name,LINETYPE *retline,bool respect_scope)
1583 #else
1584 LINE *find_named_line(name,retline,respect_scope)
1585 CHARTYPE *name;
1586 LINETYPE *retline;
1587 bool respect_scope;
1588 #endif
1589 /***********************************************************************/
1590 {
1591    LINETYPE lineno=0;
1592    LINE *curr=NULL;
1593 
1594    TRACE_FUNCTION("target.c:  find_named_line");
1595    /*
1596     * Find the line number in the current file of the named line specified
1597     */
1598    curr = CURRENT_FILE->first_line;
1599    while( curr != (LINE *)NULL )
1600    {
1601       /*
1602        * Check the line's name if we are not respecting scope or if we are
1603        * respecting scope and the line is in scope.
1604        */
1605       if ( !respect_scope
1606       || ( respect_scope && (IN_SCOPE(CURRENT_VIEW,curr) || CURRENT_VIEW->scope_all ) ) )
1607       {
1608          /*
1609           * If we don't have a first_name, ignore the line
1610           */
1611          if ( curr->first_name != NULL )
1612          {
1613             if ( find_line_name( curr, name ) != NULL )
1614             {
1615                *retline = lineno;
1616                TRACE_RETURN();
1617                return( curr );
1618             }
1619          }
1620       }
1621       lineno++;
1622       curr = curr->next;
1623    }
1624    TRACE_RETURN();
1625    return( (LINE *)NULL );
1626 }
1627 /***********************************************************************/
1628 #ifdef HAVE_PROTO
find_string_target(LINE * curr,RTARGET * rt,LENGTHTYPE start_col,int search_semantics)1629 short find_string_target( LINE *curr, RTARGET *rt, LENGTHTYPE start_col, int search_semantics )
1630 #else
1631 short find_string_target( curr, rt, start_col, search_semantics )
1632 LINE *curr;
1633 RTARGET *rt;
1634 LENGTHTYPE start_col;
1635 int search_semantics;
1636 #endif
1637 /***********************************************************************/
1638 /*
1639  * Finds a string (needle: in rt->string) in another string (haystack: in curr->line)
1640  * If SEARCHing backwards, we need to copy the string and reverse the needle and
1641  * the haystack.
1642  * e.g.
1643  * SEARCH -/abc/
1644  * where curr->line = "1234abc56" and current column position is 9 (start_col is 0 based)
1645  * needle becomes: "cba"
1646  * haystack becomes: "65cba4321"
1647  * and start_col becomes: 0 (len - start_col - 1)
1648  */
1649 {
1650    CHARTYPE *haystack=curr->line;
1651    CHARTYPE *needle;
1652    LENGTHTYPE needle_length=0,haystack_length=0;
1653    LINETYPE real_start=0,real_end=0;
1654    bool use_trec=FALSE;
1655    short rc=RC_OK;
1656    LENGTHTYPE loc=(-1);
1657    LENGTHTYPE str_length=0;
1658 
1659    TRACE_FUNCTION("target.c:  find_string_target");
1660    /*
1661     * Allocate some termporary space
1662     */
1663    needle = (CHARTYPE *)alloca( rt->length + 1 );
1664    if ( needle == NULL )
1665    {
1666       display_error( 30, (CHARTYPE *)"", FALSE );
1667       TRACE_RETURN();
1668       return(RC_OUT_OF_MEMORY);
1669    }
1670    /*
1671     * Copy the supplied string target rather than point to it, as we don't
1672     * want to change the value of the target if it is a HEX string.
1673     */
1674    strcpy((DEFCHAR*)needle,(DEFCHAR*)rt->string);
1675    /*
1676     * If HEX is on, convert the target from a HEX format to CHARTYPE.
1677     */
1678    if (CURRENT_VIEW->hex == TRUE)
1679    {
1680       rc = convert_hex_strings(needle);
1681       switch( rc )
1682       {
1683          case -1: /* invalid hex value */
1684             display_error( 32, needle, FALSE );
1685             TRACE_RETURN();
1686             return(RC_INVALID_OPERAND);
1687             break;
1688          case -2: /* memory exhausted */
1689             display_error( 30, (CHARTYPE *)"", FALSE );
1690             TRACE_RETURN();
1691             return(RC_OUT_OF_MEMORY);
1692             break;
1693          default:
1694             break;
1695       }
1696       needle_length = rc;
1697    }
1698    else
1699       needle_length = strlen((DEFCHAR *)needle);
1700    /*
1701     * Set the length of the string to be the actual length
1702     * of the string target.
1703     */
1704    rt->length = needle_length;
1705    /*
1706     * Determine if we need to copy the contents of the line into trec.
1707     * The reasons we need to do this are:
1708     * - the length of the needle is 0
1709     * - the last character of needle is a space
1710     */
1711    if ( needle_length == 0 )
1712       use_trec = TRUE;
1713    else
1714    {
1715       if ( *(needle+(needle_length-1) ) == ' ' )
1716          use_trec = TRUE;
1717    }
1718    if ( use_trec )
1719    {
1720       memset( trec, ' ', max_line_length );
1721       memcpy( trec, curr->line, curr->length );
1722       haystack = trec;
1723 /*    haystack_length = max_line_length;*/
1724       haystack_length = min( max_line_length, max( CURRENT_VIEW->zone_start, curr->length )+needle_length );
1725    }
1726    else
1727    {
1728       haystack = curr->line;
1729       haystack_length = curr->length;
1730    }
1731    /*
1732     * Calculate the bounds to search in based on length of haystack and
1733     * ZONE settings. If the haystack is empty, no need to search.
1734     */
1735    if ( haystack_length > 0 )
1736    {
1737       if ( search_semantics
1738       &&   rt->negative )
1739       {
1740          real_end = max( start_col, min( haystack_length, CURRENT_VIEW->zone_end-1 ) );
1741          real_start = min( start_col, CURRENT_VIEW->zone_end-1 );
1742       }
1743       else
1744       {
1745          real_end = min( haystack_length-1, CURRENT_VIEW->zone_end-1 );
1746          real_start = max( start_col, CURRENT_VIEW->zone_start-1 );
1747       }
1748       /*
1749        * Find the needle in the haystack if real_end > real_start
1750        */
1751       if ( real_end >= real_start )
1752       {
1753          if ( search_semantics
1754          &&   rt->negative )
1755          {
1756             LENGTHTYPE i;
1757             for( i = 0; loc == (-1) && real_start >= CURRENT_VIEW->zone_start-1; i++, real_start-- )
1758             {
1759                loc = memfind(haystack+real_start,needle,(real_end-real_start+1),
1760                        needle_length,(bool)((CURRENT_VIEW->case_locate == CASE_IGNORE) ? TRUE : FALSE),
1761                        CURRENT_VIEW->arbchar_status,
1762                        CURRENT_VIEW->arbchar_single,
1763                        CURRENT_VIEW->arbchar_multiple,
1764                        &str_length);
1765                if ( loc != (-1)
1766                &&  loc + real_start - 1 == start_col )
1767                   loc = -1;
1768             }
1769             if ( loc != (-1) )
1770             {
1771                real_start++;
1772             }
1773          }
1774          else
1775          {
1776             loc = memfind(haystack+real_start,needle,(real_end-real_start+1),
1777                        needle_length,(bool)((CURRENT_VIEW->case_locate == CASE_IGNORE) ? TRUE : FALSE),
1778                        CURRENT_VIEW->arbchar_status,
1779                        CURRENT_VIEW->arbchar_single,
1780                        CURRENT_VIEW->arbchar_multiple,
1781                        &str_length);
1782          }
1783       }
1784    }
1785    if (loc == (-1))
1786       rc = RC_TARGET_NOT_FOUND;
1787    else
1788    {
1789       rt->start = loc+real_start;
1790       rt->found_length = str_length;
1791       rc = RC_OK;
1792    }
1793    TRACE_RETURN();
1794    return(rc);
1795 }
1796 /***********************************************************************/
1797 #ifdef HAVE_PROTO
find_regexp(LINE * curr,RTARGET * rt)1798 short find_regexp(LINE *curr,RTARGET *rt)
1799 #else
1800 short find_regexp(curr,rt)
1801 LINE *curr;
1802 RTARGET *rt;
1803 #endif
1804 /***********************************************************************/
1805 {
1806    CHARTYPE *haystack=NULL;
1807    LENGTHTYPE len,i,haystack_length=0,real_start=0,real_end=0;
1808    short rc=RC_TARGET_NOT_FOUND;
1809    long re_len;
1810 
1811    TRACE_FUNCTION("target.c:  find_regexp");
1812    /*
1813     * Search for the compiled RE
1814     */
1815 
1816    haystack = curr->line;
1817    haystack_length = curr->length;
1818    /*
1819     * Calculate the bounds to search in based on length of haystack and
1820     * ZONE settings. If the haystack is empty, no need to search.
1821     */
1822    if (haystack_length == 0)
1823    {
1824       haystack = (CHARTYPE *)"";
1825       real_end = real_start = 0;
1826       len = 0;
1827    }
1828    else
1829    {
1830       real_end = min(haystack_length-1,CURRENT_VIEW->zone_end-1);
1831       real_start = max(0,CURRENT_VIEW->zone_start-1);
1832       len = real_end - real_start + 1;
1833    }
1834 
1835    for (i=0;i<len;)
1836    {
1837       re_len = re_match( &rt->pattern_buffer, (DEFCHAR *)haystack+i,len-i,0,0);
1838       if ( re_len > 0 )
1839       {
1840          rt->length = re_len;
1841          rt->start = real_start+i; /* ?? */
1842          rt->found_length = re_len;
1843          rc = RC_OK;
1844          break;
1845       }
1846       else
1847          i++;
1848    }
1849 
1850    TRACE_RETURN();
1851    return(rc);
1852 }
1853 /***********************************************************************/
1854 #ifdef HAVE_PROTO
find_rtarget_target(LINE * curr,TARGET * target,LINETYPE true_line,LINETYPE line_number,LINETYPE * num_lines)1855 short find_rtarget_target( LINE *curr, TARGET *target, LINETYPE true_line, LINETYPE line_number, LINETYPE *num_lines )
1856 #else
1857 short find_rtarget_target( curr, target, true_line, line_number, num_lines )
1858 LINE *curr;
1859 TARGET *target;
1860 LINETYPE true_line,line_number;
1861 LINETYPE *num_lines;
1862 #endif
1863 /***********************************************************************/
1864 {
1865    register short i=0;
1866    bool target_found=FALSE,status=FALSE;
1867    LINETYPE multiplier=0;
1868    short rc=RC_OK;
1869    LENGTHTYPE start_col;
1870 
1871    TRACE_FUNCTION(" target.c:  find_rtarget_target" );
1872    /*
1873     * If the line is not in scope and scope is respected, return FALSE.
1874     */
1875    if ( !(IN_SCOPE(CURRENT_VIEW,curr) )
1876    &&  !target->ignore_scope )
1877    {
1878       if (!CURRENT_VIEW->scope_all
1879       && !TOF(line_number)
1880       && !BOF(line_number))
1881       {
1882          TRACE_RETURN();
1883          return(RC_TARGET_NOT_FOUND);
1884       }
1885    }
1886    if (line_number != true_line)
1887       *num_lines = *num_lines + 1L;
1888    for ( i = 0; i < target->num_targets-((target->spare == (-1) ) ? 0 : 1); i++ )
1889    {
1890       target_found = FALSE;
1891       multiplier = (target->rt[i].negative) ? -1L : 1L;
1892       switch( target->rt[i].target_type )
1893       {
1894          case TARGET_BLANK:
1895             if ( true_line == line_number )
1896             {
1897                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
1898                break;
1899             }
1900             if ( target->rt[0].negative )
1901             {
1902                if ( curr->prev == NULL )
1903                   break;
1904             }
1905             else
1906             {
1907                if ( curr->next == NULL )
1908                   break;
1909             }
1910             target_found = is_blank( curr );
1911             break;
1912          case TARGET_NEW:
1913             if ( true_line == line_number )
1914             {
1915                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
1916                break;
1917             }
1918             if ( target->rt[0].negative )
1919             {
1920                if ( curr->prev == NULL )
1921                   break;
1922             }
1923             else
1924             {
1925                if ( curr->next == NULL )
1926                   break;
1927             }
1928             target_found = curr->flags.new_flag;
1929             break;
1930          case TARGET_CHANGED:
1931             if ( true_line == line_number )
1932             {
1933                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
1934                break;
1935             }
1936             if ( target->rt[0].negative )
1937             {
1938                if ( curr->prev == NULL )
1939                   break;
1940             }
1941             else
1942             {
1943                if ( curr->next == NULL )
1944                   break;
1945             }
1946             target_found = curr->flags.changed_flag;
1947             break;
1948          case TARGET_ALTERED:
1949             if ( true_line == line_number )
1950             {
1951                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
1952                break;
1953             }
1954             if ( target->rt[0].negative )
1955             {
1956                if ( curr->prev == NULL )
1957                   break;
1958             }
1959             else
1960             {
1961                if ( curr->next == NULL )
1962                   break;
1963             }
1964             target_found = (curr->flags.changed_flag | curr->flags.new_flag);
1965             break;
1966          case TARGET_TAGGED:
1967             if ( true_line == line_number )
1968             {
1969                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
1970                break;
1971             }
1972             if ( target->rt[0].negative )
1973             {
1974                if ( curr->prev == NULL )
1975                   break;
1976             }
1977             else
1978             {
1979                if ( curr->next == NULL )
1980                   break;
1981             }
1982             target_found = curr->flags.tag_flag;
1983             break;
1984          case TARGET_POINT:
1985             if ( curr->first_name == NULL )
1986                break;
1987             if ( find_line_name( curr, target->rt[i].string ) != NULL )
1988                target_found = TRUE;
1989             break;
1990          case TARGET_STRING:
1991             /*
1992              * If we are doing a SEARCH, start at focus column
1993              * otherwise start at 0 for locate
1994              * As focus_column is 1 based, then using focus_column
1995              * analtered is the same as adding 1, so in a backwards search
1996              * we have to subtract 1 for the previous column, and 1 to adjust
1997              * from 1 based to 0 based (-2 in total).
1998              */
1999              if ( target->search_semantics )
2000              {
2001                 if ( target->rt[0].negative )
2002                 {
2003                    if ( target->focus_column == -1L )
2004                       start_col = curr->length + strlen( (DEFCHAR *)target->rt[i].string );
2005                    else
2006                       start_col = target->focus_column-2;
2007                 }
2008                 else
2009                 {
2010                    if ( target->focus_column == -1L )
2011                       start_col = 0;
2012                    else
2013                       start_col = target->focus_column;
2014                 }
2015              }
2016              else
2017                 start_col = 0;
2018             /*
2019              * If we are processing the focus line we return immediately;
2020              * we can't match on the focus line, unless we are running
2021              * a SEARCH
2022              */
2023             if (true_line == line_number
2024             &&  target->search_semantics == FALSE )
2025             {
2026                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
2027                break;
2028             }
2029             /*
2030              * When we are SEARCHing we can't stop because the PREVIOUS
2031              * line is NULL; there still could be strings on the line
2032              * after the focus column. BUT HOW DO WE STOP ???
2033              * SEEMS OK!
2034              */
2035             if (target->rt[0].negative)
2036             {
2037                if (curr->prev == NULL)
2038                   break;
2039             }
2040             else
2041             {
2042                if (curr->next == NULL)
2043                   break;
2044             }
2045             if ( start_col == (-1) )
2046                rc = RC_TARGET_NOT_FOUND;
2047             else
2048                rc = find_string_target( curr, &target->rt[i], start_col, target->search_semantics );
2049             switch(rc)
2050             {
2051                case RC_OK:
2052                   target->rt[i].found = target_found = TRUE;
2053                   break;
2054                case RC_TARGET_NOT_FOUND:
2055                   /*
2056                    * Target not found. If this is a search, we need to reset
2057                    * the focus_column to start searching at col 0
2058                    */
2059                   target->focus_column = -1L;
2060                   break;
2061                default:
2062                   TRACE_RETURN();
2063                   return(rc);
2064                   break;
2065             }
2066             break;
2067          case TARGET_RELATIVE:
2068             /*
2069              * If the command is TAG or ALL then we mark the nth line so a match
2070              * here is based on
2071              */
2072             if ( target->all_tag_command )
2073             {
2074                if ( *num_lines % target->rt[i].numeric_target == 0 )
2075                   target_found = TRUE;
2076                break;
2077             }
2078             if ((*num_lines * multiplier) == target->rt[i].numeric_target)
2079                   target_found = TRUE;
2080             if (target->rt[0].negative)
2081             {
2082                if (curr->prev == NULL)
2083                {
2084                   target_found = TRUE;
2085                   break;
2086                }
2087             }
2088             else
2089             {
2090                if (curr->next == NULL)
2091                {
2092                   target_found = TRUE;
2093                   break;
2094                }
2095             }
2096             break;
2097          case TARGET_ABSOLUTE:
2098             if (line_number == target->rt[i].numeric_target)
2099                   target_found = TRUE;
2100             break;
2101          case TARGET_REGEXP:
2102             if (true_line == line_number)
2103             {
2104                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
2105                break;
2106             }
2107             if (target->rt[0].negative)
2108             {
2109                if (curr->prev == NULL)
2110                   break;
2111             }
2112             else
2113             {
2114                if (curr->next == NULL)
2115                   break;
2116             }
2117             rc = find_regexp(curr,&target->rt[i]);
2118             switch(rc)
2119             {
2120                case RC_OK:
2121                   target->rt[i].found = target_found = TRUE;
2122                   break;
2123                case RC_TARGET_NOT_FOUND:
2124                   break;
2125                default:
2126                   TRACE_RETURN();
2127                   return(rc);
2128                   break;
2129             }
2130             break;
2131          default:
2132             break;
2133       }
2134       if (target->rt[i].not_target)
2135          target->rt[i].found = target_found = (target_found) ? FALSE : TRUE;
2136       switch(target->rt[i].boolean)
2137       {
2138          case ' ':
2139             status = target_found;
2140             break;
2141          case '&':
2142             status &= target_found;
2143             break;
2144          case '|':
2145             status |= target_found;
2146             break;
2147       }
2148    }
2149    TRACE_RETURN();
2150    return((status)?RC_OK:RC_TARGET_NOT_FOUND);
2151 }
2152 /***********************************************************************/
2153 #ifdef HAVE_PROTO
find_rtarget_column_target(CHARTYPE * line,LENGTHTYPE len,TARGET * target,LENGTHTYPE true_column,LENGTHTYPE column_number,LINETYPE * num_columns)2154 bool find_rtarget_column_target( CHARTYPE *line, LENGTHTYPE len, TARGET *target, LENGTHTYPE true_column, LENGTHTYPE column_number, LINETYPE *num_columns )
2155 #else
2156 bool find_rtarget_column_target( line, len, target, true_column, column_number, num_columns )
2157 CHARTYPE *line;
2158 LENGTHTYPE len;
2159 TARGET *target;
2160 LENGTHTYPE true_column,column_number;
2161 LINETYPE *num_columns;
2162 #endif
2163 /***********************************************************************/
2164 {
2165    register short i=0;
2166    bool target_found=FALSE,status=FALSE;
2167    LINETYPE multiplier=0;
2168    LINE curr;
2169 
2170    TRACE_FUNCTION("target.c:  find_rtarget_column_target");
2171    if (column_number != true_column)
2172       *num_columns = *num_columns + 1L;
2173    for (i=0;i<target->num_targets-((target->spare == (-1)) ? 0 : 1);i++)
2174    {
2175       target_found = FALSE;
2176       multiplier = (target->rt[i].negative) ? -1L : 1L;
2177       switch(target->rt[i].target_type)
2178       {
2179          case TARGET_BLANK:
2180             if (true_column == column_number)
2181             {
2182                target_found = ((target->rt[i].not_target) ? TRUE : FALSE);
2183                break;
2184             }
2185             if (column_number < CURRENT_VIEW->zone_start
2186             ||  column_number > CURRENT_VIEW->zone_end)
2187             {
2188                 target_found = FALSE;
2189                 break;
2190             }
2191             if (column_number > len)
2192             {
2193                target_found = TRUE;
2194                break;
2195             }
2196             if (*(line+column_number-1) == ' ') /* should be blank word */
2197                target_found = TRUE;
2198             else
2199                target_found = FALSE;
2200             break;
2201          case TARGET_STRING:
2202             if (column_number < CURRENT_VIEW->zone_start
2203             ||  column_number > CURRENT_VIEW->zone_end
2204             ||  column_number > len )
2205             {
2206                 target_found = FALSE;
2207                 break;
2208             }
2209             /*
2210              * We need to determine if the string target starts in the
2211              * column; column_number.
2212              */
2213             curr.line = line;
2214             curr.length = len;
2215 
2216             /*
2217              * If locating backwards, start the search 2 positions to the left
2218              * of the current true_column. This is because true_column is 1 based, and
2219              * our searching is 0 based, so the first decrement is to adjust 1-based
2220              * to 0-based, and the second decrement is to put the cursor 1 position
2221              * to the left of our focus column, otherwise it will possibly match.
2222              */
2223             if ( target->rt[i].negative )
2224                true_column -= 2;
2225             if ( find_string_target( &curr, &target->rt[i], true_column, THE_SEARCH_SEMANTICS ) == RC_OK
2226             &&   target->rt[i].start+1 == column_number )
2227             {
2228                target_found = TRUE;
2229             }
2230 /*
2231 fprintf(stderr, "%s %d: col %d i %d true %d start: %d found: %d\n",
2232 __FILE__,__LINE__,column_number,i,true_column,target->rt[i].start,target_found);
2233 */
2234             break;
2235          case TARGET_ABSOLUTE:
2236             if (column_number == target->rt[i].numeric_target)
2237                target_found = TRUE;
2238             break;
2239          case TARGET_RELATIVE:
2240             if ((*num_columns * multiplier) == target->rt[i].numeric_target)
2241                target_found = TRUE;
2242             break;
2243          default:
2244             break;
2245       }
2246       if (target->rt[i].not_target)
2247          target_found = (target_found) ? FALSE : TRUE;
2248       switch(target->rt[i].boolean)
2249       {
2250          case ' ':
2251             status = target_found;
2252             break;
2253          case '&':
2254             status &= target_found;
2255             break;
2256          case '|':
2257             status |= target_found;
2258             break;
2259       }
2260    }
2261    TRACE_RETURN();
2262    return(status);
2263 }
2264 /***********************************************************************/
2265 #ifdef HAVE_PROTO
find_next_in_scope(VIEW_DETAILS * view,LINE * in_curr,LINETYPE line_number,short direction)2266 LINETYPE find_next_in_scope(VIEW_DETAILS *view,LINE *in_curr,LINETYPE line_number,short direction)
2267 #else
2268 LINETYPE find_next_in_scope(view,in_curr,line_number,direction)
2269 VIEW_DETAILS *view;
2270 LINE *in_curr;
2271 LINETYPE line_number;
2272 short direction;
2273 #endif
2274 /***********************************************************************/
2275 {
2276    LINE *curr=in_curr;
2277 
2278    TRACE_FUNCTION("target.c:  find_next_in_scope");
2279    if (in_curr == NULL)
2280       curr = lll_find(CURRENT_FILE->first_line,CURRENT_FILE->last_line,line_number,CURRENT_FILE->number_lines);
2281    for (;;line_number+=(LINETYPE)direction)
2282    {
2283       if (IN_SCOPE(view,curr))
2284          break;
2285       if (direction == DIRECTION_FORWARD)
2286          curr = curr->next;
2287       else
2288          curr = curr->prev;
2289       if (curr == NULL)
2290          break;
2291    }
2292    TRACE_RETURN();
2293    return(line_number);
2294 }
2295 /***********************************************************************/
2296 #ifdef HAVE_PROTO
find_last_not_in_scope(VIEW_DETAILS * view,LINE * in_curr,LINETYPE line_number,short direction)2297 LINETYPE find_last_not_in_scope(VIEW_DETAILS *view,LINE *in_curr,LINETYPE line_number,short direction)
2298 #else
2299 LINETYPE find_last_not_in_scope(view,in_curr,line_number,direction)
2300 VIEW_DETAILS *view;
2301 LINE *in_curr;
2302 LINETYPE line_number;
2303 short direction;
2304 #endif
2305 /***********************************************************************/
2306 {
2307    LINE *curr=in_curr;
2308    LINETYPE offset=0L;
2309 
2310    TRACE_FUNCTION("target.c:  find_last_not_in_scope");
2311    if (in_curr == NULL)
2312       curr = lll_find(CURRENT_FILE->first_line,CURRENT_FILE->last_line,line_number,CURRENT_FILE->number_lines);
2313    for (;;line_number+=(LINETYPE)direction)
2314    {
2315       if (IN_SCOPE(view,curr))
2316          break;
2317       if (direction == DIRECTION_FORWARD)
2318       {
2319          curr = curr->next;
2320          offset = (-1L);
2321       }
2322       else
2323       {
2324          curr = curr->prev;
2325          offset = 1L;
2326       }
2327       if (curr == NULL)
2328          break;
2329    }
2330    TRACE_RETURN();
2331    return(line_number+offset);
2332 }
2333 /***********************************************************************/
2334 #ifdef HAVE_PROTO
validate_target(CHARTYPE * string,TARGET * target,long target_type,LINETYPE true_line,bool display_parse_error,bool allow_error_display)2335 short validate_target(CHARTYPE *string,TARGET *target,long target_type,LINETYPE true_line,bool display_parse_error,bool allow_error_display)
2336 #else
2337 short validate_target(string,target,target_type,true_line,display_parse_error,allow_error_display)
2338 CHARTYPE *string;
2339 TARGET *target;
2340 long target_type;
2341 LINETYPE true_line;
2342 bool display_parse_error,allow_error_display;
2343 #endif
2344 /***********************************************************************/
2345 {
2346    short rc=RC_OK;
2347 
2348    TRACE_FUNCTION("target.c:  validate_target");
2349    rc = parse_target(string,true_line,target,target_type,display_parse_error,allow_error_display,FALSE);
2350    if (rc != RC_OK)
2351    {
2352       TRACE_RETURN();
2353       return(rc);
2354    }
2355    rc = find_target(target,true_line,display_parse_error,allow_error_display);
2356    if (rc != RC_OK)
2357    {
2358       TRACE_RETURN();
2359       return(RC_TARGET_NOT_FOUND);
2360    }
2361    TRACE_RETURN();
2362    return(RC_OK);
2363 }
2364 #ifdef NOT_USED_ANYMORE
2365 /***********************************************************************/
2366 #ifdef HAVE_PROTO
in_scope(VIEW_DETAILS * view,LINE * curr)2367 bool in_scope(VIEW_DETAILS *view,LINE *curr)
2368 #else
2369 bool in_scope(view,curr)
2370 VIEW_DETAILS *view;
2371 LINE *curr;
2372 #endif
2373 /***********************************************************************/
2374 {
2375    bool rc=RC_OK;
2376 
2377    TRACE_FUNCTION("target.c:  in_scope");
2378    if (curr->select < view->display_low
2379    ||  curr->select > view->display_high)
2380       rc = FALSE;
2381    else
2382       rc = TRUE;
2383    TRACE_RETURN();
2384    return(rc);
2385 }
2386 #endif
2387 /***********************************************************************/
2388 #ifdef HAVE_PROTO
calculate_scroll_values(CHARTYPE curr_screen,VIEW_DETAILS * curr_view,short * number_focus_rows,LINETYPE * new_focus_line,LINETYPE * new_current_line,bool * limit_of_screen,bool * limit_of_file,bool * leave_cursor,short direction)2389 void calculate_scroll_values(CHARTYPE curr_screen, VIEW_DETAILS *curr_view, short *number_focus_rows,LINETYPE *new_focus_line,
2390                              LINETYPE *new_current_line,bool *limit_of_screen,
2391                              bool *limit_of_file,bool *leave_cursor,
2392                              short direction)
2393 #else
2394 void calculate_scroll_values(curr_screen,curr_view,number_focus_rows,new_focus_line,new_current_line,
2395                              limit_of_screen,limit_of_file,leave_cursor,direction)
2396 CHARTYPE curr_screen;
2397 VIEW_DETAILS *curr_view;
2398 short *number_focus_rows;
2399 LINETYPE *new_focus_line,*new_current_line;
2400 bool *limit_of_screen,*limit_of_file,*leave_cursor;
2401 short direction;
2402 #endif
2403 /***********************************************************************/
2404 {
2405    register short i=0;
2406    unsigned short y=0;
2407 
2408    TRACE_FUNCTION("target.c:  calculate_scroll_values");
2409 
2410    *limit_of_screen = *limit_of_file = FALSE;
2411    *number_focus_rows = 0;
2412    *new_focus_line = (-1L);
2413    y = screen[curr_screen].rows[WINDOW_FILEAREA];
2414    switch(direction)
2415    {
2416       case DIRECTION_FORWARD:
2417          /*
2418           * Determine the new focus line and the number of rows to adjust the
2419           * cursor position.
2420           */
2421          for (i=0;i<screen[curr_screen].rows[WINDOW_FILEAREA];i++)
2422          {
2423             if (screen[curr_screen].sl[i].line_number == curr_view->focus_line)
2424             {
2425                y = i;
2426                continue;
2427             }
2428             if (screen[curr_screen].sl[i].line_number != (-1L)
2429             && y != screen[curr_screen].rows[WINDOW_FILEAREA])
2430             {
2431                *number_focus_rows = i-y;
2432                *new_focus_line = screen[curr_screen].sl[i].line_number;
2433                break;
2434             }
2435          }
2436          /*
2437           * If we have NOT set a new focus line (because we are on the bottom
2438           * of the screen) the new focus line is the next line in scope (if
2439           * SHADOW is OFF). If SHADOW is ON, the new focus line is determined by
2440           * the status of the current focus line.
2441           */
2442          if (*new_focus_line == (-1L))
2443          {
2444             if (curr_view->shadow)
2445             {
2446                *new_focus_line = screen[curr_screen].sl[y].line_number +
2447                                  ((screen[curr_screen].sl[y].number_lines_excluded == 0) ?
2448                                  1L :
2449                                  (LINETYPE)screen[curr_screen].sl[y].number_lines_excluded);
2450             }
2451             else
2452             {
2453                if (screen[curr_screen].sl[y].current->next != NULL)
2454                   *new_focus_line = find_next_in_scope(curr_view,screen[curr_screen].sl[y].current->next,
2455                                    screen[curr_screen].sl[y].line_number+1L,direction);
2456             }
2457          }
2458          /*
2459           * Determine the new current line and the number of rows to adjust the
2460           * cursor position.
2461           */
2462          *leave_cursor = TRUE;
2463          *new_current_line = (-1L);
2464          for (i=curr_view->current_row+1;i<screen[curr_screen].rows[WINDOW_FILEAREA];i++)
2465          {
2466             if (screen[curr_screen].sl[i].line_type == LINE_LINE
2467             ||  screen[curr_screen].sl[i].line_type == LINE_TOF   /* MH12 */
2468             ||  screen[curr_screen].sl[i].line_type == LINE_EOF)  /* MH12 */
2469             {
2470                *new_current_line = screen[curr_screen].sl[i].line_number;
2471                break;
2472             }
2473             if (screen[curr_screen].sl[i].line_type == LINE_SHADOW)
2474                *leave_cursor = FALSE;
2475          }
2476          /*
2477           * If we have NOT set a new current line (only way this can happen is
2478           * if all lines after the current line are RESERVED, SCALE or TABLINE)
2479           * and the cursor is on the current line) the new current line is the
2480           * next line in scope.
2481           */
2482          if (*new_current_line == (-1L))
2483          {
2484             if (screen[curr_screen].sl[y].current->next != NULL)
2485                *new_current_line = find_next_in_scope(curr_view,screen[curr_screen].sl[y].current->next,
2486                                    screen[curr_screen].sl[y].line_number+1L,direction);
2487          }
2488          /*
2489           * Set flags for bottom_of_screen and bottom_of_file as appropriate.
2490           */
2491          if (*number_focus_rows == 0)
2492             *limit_of_screen = TRUE;
2493 /*         if (screen[curr_screen].sl[y].line_type == LINE_TOF_EOF MH12 */
2494 /*         &&  screen[curr_screen].sl[y].current->next == NULL) MH12 */
2495          if (screen[curr_screen].sl[y].line_type == LINE_EOF)
2496             *limit_of_file = TRUE;
2497          break;
2498       case DIRECTION_BACKWARD:
2499          /*
2500           * Determine the new focus line and the number of rows to adjust the
2501           * cursor position.
2502           */
2503          for (i=screen[curr_screen].rows[WINDOW_FILEAREA]-1;i>-1;i--)
2504          {
2505             if (screen[curr_screen].sl[i].line_number == curr_view->focus_line)
2506             {
2507                y = i;
2508                continue;
2509             }
2510             if (screen[curr_screen].sl[i].line_number != (-1L)
2511             && y != screen[curr_screen].rows[WINDOW_FILEAREA])
2512             {
2513                *number_focus_rows = y-i;
2514                *new_focus_line = screen[curr_screen].sl[i].line_number;
2515                break;
2516             }
2517          }
2518          /*
2519           * If we have NOT set a new focus line (because we are on the top
2520           * of the screen) the new focus line is the prev line in scope (if
2521           * SHADOW is OFF). If SHADOW is ON, the new focus line is determined by
2522           * the status of the current focus line.
2523           */
2524          if (*new_focus_line == (-1L))
2525          {
2526             if (curr_view->shadow)
2527             {
2528                if (screen[curr_screen].sl[y].line_type == LINE_SHADOW)
2529                   *new_focus_line = screen[curr_screen].sl[y].line_number - 1L;
2530                else
2531                {
2532                   if (screen[curr_screen].sl[y].current->prev != NULL)
2533                   {
2534                      *new_focus_line = find_next_in_scope(curr_view,screen[curr_screen].sl[y].current->prev,
2535                                        screen[curr_screen].sl[y].line_number-1L,direction);
2536                      if (*new_focus_line != screen[curr_screen].sl[y].line_number-1L)
2537                         *new_focus_line = *new_focus_line + 1;
2538                   }
2539                }
2540             }
2541             else
2542             {
2543                if (screen[curr_screen].sl[y].current->prev != NULL)
2544                   *new_focus_line = find_next_in_scope(curr_view,screen[curr_screen].sl[y].current->prev,
2545                                    screen[curr_screen].sl[y].line_number-1L,direction);
2546             }
2547          }
2548          /*
2549           * Determine the new current line and the number of rows to adjust the
2550           * cursor position.
2551           */
2552          *leave_cursor = TRUE;
2553          *new_current_line = (-1L);
2554          for (i=curr_view->current_row-1;i>-1;i--)
2555          {
2556             if (screen[curr_screen].sl[i].line_type == LINE_LINE
2557             ||  screen[curr_screen].sl[i].line_type == LINE_TOF /* MH12 */
2558             ||  screen[curr_screen].sl[i].line_type == LINE_EOF) /* MH12 */
2559             {
2560                *new_current_line = screen[curr_screen].sl[i].line_number;
2561                break;
2562             }
2563             if (screen[curr_screen].sl[i].line_type == LINE_SHADOW)
2564                *leave_cursor = FALSE;
2565          }
2566          /*
2567           * If we have NOT set a new current line (only way this can happen is
2568           * if all lines before the current line are RESERVED, SCALE or TABLINE)
2569           * and the cursor is on the current line) the new current line is the
2570           * previous line in scope.
2571           */
2572          if (*new_current_line == (-1L))
2573          {
2574             if (screen[curr_screen].sl[y].current->prev != NULL)
2575                *new_current_line = find_next_in_scope(curr_view,screen[curr_screen].sl[y].current->prev,
2576                                   screen[curr_screen].sl[y].line_number-1L,direction);
2577             else
2578                *new_current_line = *new_focus_line;
2579          }
2580          /*
2581           * Set flags for top_of_screen and top_of_file as appropriate.
2582           */
2583          if (*number_focus_rows == 0)
2584             *limit_of_screen = TRUE;
2585 /*         if (screen[curr_screen].sl[y].line_type == LINE_TOF_EOF MH12 */
2586 /*         &&  screen[curr_screen].sl[y].current->prev == NULL) MH12 */
2587          if (screen[curr_screen].sl[y].line_type == LINE_TOF)
2588             *limit_of_file = TRUE;
2589          break;
2590    }
2591    TRACE_RETURN();
2592    return;
2593 }
2594 /***********************************************************************/
2595 #ifdef HAVE_PROTO
find_last_focus_line(CHARTYPE curr_screen,unsigned short * newrow)2596 short find_last_focus_line( CHARTYPE curr_screen, unsigned short *newrow)
2597 #else
2598 short find_last_focus_line( curr_screen, newrow )
2599 CHARTYPE curr_screen;
2600 unsigned short *newrow;
2601 #endif
2602 /***********************************************************************/
2603 {
2604    register short i=0;
2605    short row=(-1);
2606    short rc=RC_OK;
2607 
2608    TRACE_FUNCTION("target.c:  find_last_focus_line");
2609    for ( i = screen[curr_screen].rows[WINDOW_FILEAREA]-1; i > -1; i-- )
2610    {
2611       if ( screen[curr_screen].sl[i].line_number != (-1L) )
2612       {
2613          *newrow = row = i;
2614          break;
2615       }
2616    }
2617    if ( row == (-1) )
2618       rc = RC_INVALID_OPERAND;
2619    TRACE_RETURN();
2620    return(rc);
2621 }
2622 /***********************************************************************/
2623 #ifdef HAVE_PROTO
find_first_focus_line(CHARTYPE curr_screen,unsigned short * newrow)2624 short find_first_focus_line( CHARTYPE curr_screen, unsigned short *newrow )
2625 #else
2626 short find_first_focus_line( curr_screen, newrow )
2627 CHARTYPE curr_screen;
2628 unsigned short *newrow;
2629 #endif
2630 /***********************************************************************/
2631 {
2632    register short i=0;
2633    short row=(-1);
2634    short rc=RC_OK;
2635 
2636    TRACE_FUNCTION("target.c:  find_first_focus_line");
2637    for ( i = 0; i < screen[curr_screen].rows[WINDOW_FILEAREA]; i++ )
2638    {
2639       if ( screen[curr_screen].sl[i].line_number != (-1L) )
2640       {
2641          *newrow = row = i;
2642          break;
2643       }
2644    }
2645    if (row == (-1))
2646       rc = RC_INVALID_OPERAND;
2647    TRACE_RETURN();
2648    return(rc);
2649 }
2650 /***********************************************************************/
2651 #ifdef HAVE_PROTO
find_unique_char(CHARTYPE * str)2652 CHARTYPE find_unique_char(CHARTYPE *str)
2653 #else
2654 CHARTYPE find_unique_char(str)
2655 CHARTYPE *str;
2656 #endif
2657 /***********************************************************************/
2658 {
2659    register short i=0;
2660 
2661    TRACE_FUNCTION("target.c:  find_unique_char");
2662    for (i=254;i>0;i--)
2663    {
2664       if (strzeq(str,(CHARTYPE)i) == (-1))
2665       {
2666          TRACE_RETURN();
2667          return((CHARTYPE)i);
2668       }
2669    }
2670    TRACE_RETURN();
2671    return(0);
2672 }
2673