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