1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4
5 #include "ftnchek.h"
6 #include "symtab.h"
7 #include "tokdefs.h"
8 #include "forlex.h"
9 #include "advance.h"
10
11 PROTO(PRIVATE void find_comments,(srcLine *Buf));
12 PROTO(PRIVATE void find_fixed_contins,(srcLine *Buf));
13 PROTO(PRIVATE void find_free_contins,(srcLine *Buf));
14 PROTO(PRIVATE int line_is_blank,(char *s));
15
16
17 /* Function to read in a source file and store it in a linked
18 list of srcLine elements. Returns pointer to head of the
19 list. If file is empty, returns NULL.
20 */
21
22 srcLine*
gulp_srcfile(FILE * fd)23 gulp_srcfile(FILE *fd)
24 {
25 char linebuf[MAXLINE+1];
26 LINENO_t line_num=0;
27 int line_len;
28 srcLine *firstLine=NULL, *prevLine=NULL, *thisLine;
29
30 while( fgets(linebuf, sizeof(linebuf), fd ) != NULL ) {
31 LINENO_t new_line_num = 0;
32
33 line_len = strlen(linebuf); /* this counts the \n */
34
35 /* If input line was too long to fit into
36 buffer, gobble what was not read and
37 discard it. */
38 if(line_len == MAXLINE && linebuf[MAXLINE-1] != ENDL) {
39 int c;
40 while( (c = getc(fd)) != ENDL && c != EOF )
41 continue;
42 }
43 else {
44 /* Replace \n by null. line_len>0 is guaranteed */
45 if(linebuf[line_len-1] == ENDL)
46 linebuf[--line_len] = '\0';
47
48 /* handle <CR><LF> */
49 if( line_len > 1 && linebuf[line_len-1] == '\r' ) {
50 linebuf[--line_len] = '\0';
51 }
52 }
53
54 /* Allocate a new struct for this line */
55 if( (thisLine = (srcLine *)malloc(sizeof(srcLine))) == (srcLine *)NULL ||
56 (thisLine->line = (char *)malloc(line_len+1)) == (char *)NULL ) {
57 fflush(list_fd);
58 fprintf(stderr,"Oops: Out of memory in gulp_srcfile\n");
59 exit(1);
60 }
61
62 /* Remember the first line as header */
63 if( firstLine == NULL )
64 firstLine = thisLine;
65
66 /* Fill in the struct */
67 strcpy(thisLine->line,linebuf);
68
69 ++line_num; /* Advance the line count */
70
71 thisLine->line_num = line_num;
72 thisLine->printed = FALSE;
73 thisLine->contin = FALSE; /* this will be set by lexer */
74 thisLine->cpp_line_directive = FALSE;
75
76 /* Link it into the list */
77 if( prevLine != NULL )
78 prevLine->next = thisLine;
79 thisLine->prev = prevLine;
80 thisLine->next = NULL;
81 prevLine = thisLine;
82
83 /* Let # line directives override the above
84 increment of line_num. The given value
85 will take effect on the line following
86 the # line directive.
87 */
88 if( linebuf[0] == '#' ) {
89 char *s = linebuf;
90 do { ++s; } while( isspace(*s) ); /* Skip space after the '#' */
91
92 if(strncmp(s,"line",4) == 0) { /* Look for the keyword "line" */
93 s += 4; /* Skip the word "line" */
94 while( isspace(*s) ) ++s; /* Skip space after the word "line" */
95 }
96
97 if( isdigit(*s) ) { /* See that we are now looking at a number */
98 /* Get the line number */
99 new_line_num=0;
100 while( isdigit(*s) )
101 new_line_num = new_line_num*10 + BCD(*s++);
102
103 thisLine->cpp_line_directive = TRUE; /* Note we did it */
104 }
105 }
106
107 if( new_line_num != 0 ) { /* This is a # line directive */
108 line_num = new_line_num-1; /* number it 1 less than next */
109 }
110
111 }
112 (void) fclose(fd);
113
114 /* Now go thru and mark comment and continuation lines */
115 if( firstLine != (srcLine *)NULL ) {
116 find_comments(firstLine);
117 if( free_form ) { /* free source form */
118 find_free_contins(firstLine);
119 }
120 else { /* fixed source form */
121 find_fixed_contins(firstLine);
122 }
123 }
124 #ifdef DEBUG_GULP_SRCFILE
125 if(debug_latest) { /* print the source file marking comments & contins */
126 srcLine *p;
127 for(p = firstLine; p != NULL; p = p->next ) {
128 fprintf(list_fd,"\n%4d%c", p->line_num,
129 p->comment?(p->f90_comment?'!':'C'): (p->contin?'&':' ') );
130 fprintf(list_fd,"%s",p->line);
131 if(! p->comment ) {
132 int i, last_i;
133 last_i = strlen(p->line)-1;
134 if(last_i < p->start_index)
135 last_i = p->start_index;
136 if(last_i < p->end_index)
137 last_i = p->end_index;
138 if(last_i >= MAXLINE) /* just in case something's bogus */
139 last_i = MAXLINE-1;
140 for(i=0; i<=last_i; i++)
141 linebuf[i] = ' ';
142 if( p->start_index >= MAXLINE || p->end_index >= MAXLINE )
143 linebuf[last_i] = '!'; /* signals a bug */
144 else {
145 if(p->start_index == p->end_index) /* coincident */
146 linebuf[p->start_index] = '%';
147 else {
148 linebuf[p->start_index] = '^'; /* points to start */
149 linebuf[p->end_index] = '$'; /* points to end */
150 }
151 }
152 linebuf[last_i+1] = '\0';
153 fprintf(list_fd,"\n%5s","");
154 fprintf(list_fd,"%s",linebuf);
155 }
156 #include "PRINT_srcBuf.h"
157 PRINT_srcBuf(p);
158 }
159 }
160 #endif
161 return firstLine;
162 }
163
164
165 /* Function to find lines that are entirely comment (incl blank lines) */
166
167 PRIVATE void
find_comments(srcLine * Buf)168 find_comments(srcLine *Buf)
169 {
170 while( Buf != (srcLine *)NULL ) {
171 char *s = Buf->line;
172 int i,c= makeupper(s[0]);
173 int allspace;
174 COLNO_t col;
175
176 Buf->comment = FALSE;
177 Buf->blank = FALSE;
178 Buf->d_comment = FALSE;
179 Buf->f90_comment = FALSE;
180 Buf->empty_contin = FALSE;
181
182
183 if( !free_form ) {
184 /* Handle F77 standard comments here. */
185 if( c == 'C' || c == '*' )
186 Buf->comment = TRUE;
187
188 /* Tolerate D comment lines. There is
189 no provision for optionally
190 treating them as source code lines.
191 */
192 if( c == 'D' ) {
193 Buf->comment = TRUE;
194 Buf->d_comment = TRUE;
195 }
196 }
197 /* Now see if line is blank or only contains
198 an inline comment.
199 */
200 allspace = TRUE;
201 for(i=0,col=1; s[i] != '\0'; i++) {
202 if( !isspace(s[i]))
203 {
204 allspace = FALSE;
205 /* Initial "!" starts a comment, except in col. 6 of
206 fixed form it must be taken as continuation mark */
207 if(s[i]==INLINE_COMMENT_CHAR && (free_form || col != 6) ) {
208 Buf->comment = TRUE;
209 Buf->f90_comment = TRUE;
210 }
211 /* Standard 3.3.1.3 prohibits an & on a line with nothing but
212 blanks or commentary. We allow it but flag it here.
213 It is treated as a comment rather than a continuation.
214 */
215 else if( s[i] == '&' && free_form ) {
216 i++;
217 while( s[i] != '\0' && (isspace(s[i])) ) {
218 i++;
219 }
220 if( s[i] == '\0' || s[i] == INLINE_COMMENT_CHAR ) {
221 Buf->f90_comment = (s[i] == INLINE_COMMENT_CHAR);
222 Buf->comment = TRUE; /* treat as comment line */
223 Buf->empty_contin = TRUE;
224 }
225 else
226 break;
227 }
228 else
229 break;
230 }
231 else {
232 col = NXTCOL(s[i],col);
233 }
234 } /* end for */
235 if( allspace ) {
236 Buf->blank = TRUE; /* blank line */
237 Buf->comment = TRUE;
238 }
239
240 #if 0
241 fprintf(list_fd,"\n%c",Buf->comment? 'C':(Buf->contin?'&':' '));
242 fprintf(list_fd,"%s",Buf->line);
243 #endif
244 Buf = Buf->next; /* advance to next line */
245 }
246 }
247
248 /* Functions to find and mark continuation lines. Note that
249 first line of continued statement is NOT marked.
250
251 These functions also set the cursors start_index and
252 end_index of each line to the first and last significant
253 character respectively of line. (It is possible for
254 start_index to point to '\0' in some cases. Also,
255 end_index is set to -1 for fixed-form continuation line
256 that is blank.) For comment lines, the cursors are set to
257 harmless values, but they should not be needed. The column
258 number start_col corresponding to start_index after
259 accounting for tabs (including -source=dec-tab convention)
260 is also set, but there is no need for an end_col.
261
262 The main difference between the two functions, besides the
263 fundamental one of the free-form final '&' vs. fixed-form
264 column-6 mark, is that in fixed-form we need to ignore
265 spaces and pay attention to column numbers to avoid running
266 past column 72 (or in general max_stmt_col).
267
268 These functions would be simple except that a '!' or '&'
269 must not be treated as ending a line if it is inside a
270 string or a hollerith. (In this comment, an H edit
271 descriptor is considered a hollerith.) Strings are pretty
272 easy to deal with, but holleriths cause a lot of trouble.
273 In order not to see a hollerith in a variable like X1H1 or
274 in DO 4 H=1,10 we require it to be preceded by a
275 punctuation character. It is worth noting that the code
276 allows a hollerith to immediately follow a string, which is
277 improper but accepted by some compilers (and our
278 lexer/parser) in a FORMAT. I believe that all cases where
279 a hollerith could be matched by this code in a place where
280 no hollerith should be are illegal, so all we need to do is
281 make the parser squawk, which will happen. Likewise it
282 will always spot a hollerith if it sees an integer preceded
283 by punctuation and followed by 'H', which can never miss
284 a valid one. In any event a false identification or
285 failure to identify a hollerith can only cause trouble if a
286 '!' or (for free-form) '&' is in the span of the (real or
287 falsely supposed) hollerith.
288
289 In both functions (free and fixed versions) the variable
290 inside_number is set TRUE while scanning an integer that
291 could be the length part of a hollerith; num_val accumulates
292 the value of this integer; prev_sig_char remembers the previous
293 significant character, which must be punctuation (ispunct)
294 in order for inside_number to be turned on by seeing a digit.
295
296 Similarly, inside_quote is TRUE while scanning a string,
297 and quoteChar remembers the opening quote type (' or ") to
298 determine when the closing quote is found.
299 */
300
301 PRIVATE void
find_free_contins(srcLine * Buf)302 find_free_contins(srcLine *Buf)
303 {
304 int to_be_continued = FALSE; /* remembers '&' of previous line */
305 int inside_quote = FALSE;
306 int quoteChar; /* opening quote character */
307 int inside_number = FALSE; /* used for continued hollerith numbers */
308 int prev_sig_char = ' '; /* previous significant character */
309 int num_val; /* value of number recently seen */
310 while( Buf != (srcLine *)NULL ) {
311 Buf->overlength = FALSE;
312 if( Buf->comment) { /* skip comment lines */
313 Buf->contin = FALSE;
314 Buf->start_index = 0;
315 Buf->end_index = -1;
316 Buf->start_col = 0;
317 }
318 else { /* not comment */
319 COLNO_t col;
320 int i, c;
321 char *s = Buf->line;
322
323 Buf->contin = to_be_continued; /* mark this line */
324 Buf->end_index = -1;
325
326 /* look for optional initial '&' on continued line */
327 i = 0;
328 col = 1;
329 if( inside_quote ) {
330 /* Record the start of significant text.
331 Inside a quote: line must be continued, and
332 these may be overruled by finding a leading
333 '&' later (which std requires but we don't) .
334 */
335 Buf->start_index = i;
336 Buf->start_col = col;
337 Buf->contin_wo_amp = TRUE;
338 }
339 while( isspace(s[i]) ) {/* skip leading space */
340 col = NXTCOL(s[i],col);
341 i++;
342 }
343
344 if( to_be_continued ) { /* deal with continued statements */
345 if( s[i] == '&' ) {
346 Buf->contin_wo_amp = FALSE;
347 i++; /* resume after the '&' */
348 col++;
349 if( inside_quote ) { /* blanks are significant inside strings */
350 Buf->start_index = i;
351 Buf->start_col = col;
352 }
353 }
354
355 /* Handle the unlikely case that a hollerith is split
356 within or just after the initial number.
357 The usual case is to skip over blanks
358 following the initial '&' if any.
359 */
360 if( ! inside_number ||
361 !( (i == 0 || s[i-1] == '&') &&
362 (makeupper(s[i]) == 'H' || isdigit(s[i])) ) ) {
363 inside_number = FALSE;
364 while( isspace(s[i]) ) {/* skip space after & */
365 col = NXTCOL(s[i],col);
366 i++;
367 }
368 }
369 }
370 else {
371 inside_quote = FALSE; /* clean up unfinished business */
372 inside_number = FALSE;
373 prev_sig_char = ' ';
374 }
375
376 /* Record the start of significant text.
377 Continued quoted strings were handled
378 above; all other situations are done here.
379 We have at all events skipped over all
380 leading space and, if a continuation line,
381 over any initial '&' and following nonquoted space.
382 */
383 if( ! inside_quote ) {
384 Buf->start_index = i;
385 Buf->start_col = col;
386 }
387
388 to_be_continued = FALSE;
389 for( ; (c=s[i]) != '\0'; i++ ) {
390 if( inside_quote ) {
391 if( c == quoteChar ) {
392 if( s[i+1] == quoteChar ) { /* escaped quote */
393 i++;
394 col++;
395 }
396 else
397 inside_quote = FALSE;
398 }
399 /* inside quote '&' is continuation if rest of line blank */
400 else if( c == '&' && line_is_blank(s+i+1) ) {
401 to_be_continued = TRUE;
402 break;
403 }
404 /* escaped quote via Unix backslash */
405 else if( source_unix_backslash &&
406 c == '\\' && s[i+1] == quoteChar ) {
407 i++;
408 col++;
409 }
410 }
411 else if( c == '\'' || c == '"' ) {
412 inside_quote = TRUE;
413 quoteChar = c;
414 inside_number = FALSE;
415 }
416 /* Not in a quoted string or starting one */
417
418 else {
419 if( isdigit(c) ) { /* number found: see if hollerith */
420 if( inside_number ) { /* this may be a continued number */
421 num_val = num_val*10 + BCD(c);
422 }
423 else {
424 /* hollerith can only follow punctuation */
425 if( ispunct(prev_sig_char) ) {
426 num_val=BCD(c); /* start it off */
427 inside_number = TRUE;
428 }
429 }
430 }
431 if( inside_number ) {
432 if( ! (isdigit(c) || c == '&') ) {
433 inside_number = FALSE; /* cannot be continued */
434 }
435 if( makeupper(c) == 'H' ) { /* skip past hollerith */
436 int hollerith_count=0;
437 /* We can't just say i += num since line may end
438 before then. (AFAIK holleriths cannot be
439 continued in free form, so premature end of line
440 can be taken as end of stmt.) */
441 i++; col++; /* move past 'H' */
442 for(hollerith_count = num_val;
443 (c=s[i]) != '\0' && hollerith_count>0 ;
444 /* Hmmm: how should tabs in holleriths be counted?
445 As one column or many? We say many. */
446 hollerith_count--, i++, col = NXTCOL(c,col)) {
447 Buf->end_index = i;
448 }
449 hollerith_count = 0; /* if line ends before H does */
450 }
451 } /* end of dealing with number and maybe hollerith */
452
453 /* Start of a comment: quit i loop. */
454 if( c == INLINE_COMMENT_CHAR ) {
455 Buf->f90_comment = TRUE;
456 break;
457 }
458 else if( c == '&' ) {
459 /* Found freeform contin mark. Check
460 * that naught but comments follow.
461 */
462 to_be_continued = TRUE;
463
464 for(i++, col++; (c=s[i]) != '\0' && isspace(c);
465 i++, col = NXTCOL(c,col))
466 continue;
467 /* If something does follow the contin mark, set
468 end_index to point to it so the parser will squawk.
469 This error is too rare to deserve specific handling.
470 */
471 if(c == INLINE_COMMENT_CHAR)
472 Buf->f90_comment = TRUE;
473 else if(c != '\0')
474 Buf->end_index = i;
475
476 break;
477 }
478 } /* end of stuff outside quotes */
479
480 /* Re-test for end of stmt needed here due to
481 advancing i above. This should never happen
482 when inside_quote but source may be illegal.
483 */
484 if( c == '\0' )
485 break;
486
487 /* As long as interesting stuff is seen,
488 * update end index. This should never
489 * leave end_index at -1 since we know line
490 * is not a comment so not all blank.
491 */
492 if( inside_quote || ! isspace(c) ) {
493 Buf->end_index = i;
494 prev_sig_char = c;
495 /* set up std violation warning if significant
496 chars past std max line length */
497 if( col > std_max_stmt_col )
498 Buf->overlength = TRUE;
499 }
500 } /* end for i */
501 } /* end else not comment */
502 Buf = Buf->next;
503 } /* end while Buf */
504 }/*find_free_contins*/
505
506 PRIVATE void
find_fixed_contins(srcLine * Buf)507 find_fixed_contins(srcLine *Buf)
508 {
509 int inside_quote = FALSE;
510 int quoteChar; /* opening quote character */
511 int hollerith_count=0; /* used to deal with continued holleriths */
512 int inside_number = FALSE; /* used for continued hollerith numbers */
513 int prev_sig_char = ' '; /* previous significant character */
514 int num_val; /* value of number recently seen */
515 int tab_count = 0; /* tabs seen, for -port=tab option */
516 while( Buf != (srcLine *)NULL ) {
517 Buf->overlength = FALSE;
518 Buf->contin = FALSE;
519 if( Buf->comment) { /* skip comment lines */
520 Buf->start_index = 0;
521 Buf->end_index = -1;
522 Buf->start_col = 0;
523 }
524 else {
525 COLNO_t col;
526 int i,c;
527 char *s = Buf->line;
528
529 /* Handle DEC tabs: followed by nonzero digit
530 is a continuation line */
531 if( source_dec_tab && s[0] == '\t' ) {
532 ++tab_count;
533 if( isadigit((int)s[1]) && s[1] != '0' ) {
534 Buf->contin = TRUE;
535 Buf->start_index = 2; /* stmt char after contin mark */
536 Buf->start_col = 8; /* treat start of stmt as col 8 */
537 }
538 }
539 else
540 {
541 /* skip to col 6 */
542 for(i=0,col=1; col < 6 && s[i] != '\0'; i++) {
543 col = PORT_NXTCOL(s[i],col);
544 }
545 c = s[i];
546
547 if( col == 6 && c != '\0'
548 && !isspace(c) && c != '0'
549 #ifdef ALLOW_UNIX_CPP
550 /* Veto if it is a preprocessor line */
551 && s[0] != '#'
552 #endif
553 ) {
554 Buf->contin = TRUE;
555 Buf->start_index = i+1; /* record where stmt resumes */
556 Buf->start_col = 7;
557 }
558 }
559
560 /* Locate the start and end of significant
561 * source text. */
562
563
564 if( Buf->contin ) { /* resume after any continuation mark */
565 i=Buf->start_index;
566 col=Buf->start_col;
567 }
568 else {
569 /* For DEC tabs, an initial tab puts us in column 7 */
570 #ifdef DEC_TABS
571 if( source_dec_tab && s[0] == '\t' )
572 {
573 i = 1;
574 col = 7;
575 }
576 else
577 #endif
578 {
579 i=0; /* otherwise start at column 1 */
580 col=1;
581 }
582 hollerith_count = 0; /* clear unfinished business */
583 inside_quote = FALSE;
584 inside_number = FALSE;
585 prev_sig_char = ' ';
586 }
587 if( hollerith_count>0 ) {
588 for(; /* Eat any continued hollerith */
589 (c=s[i]) != '\0' && hollerith_count>0 && col<=max_stmt_col;
590 hollerith_count--, i++, col=PORT_NXTCOL(c,col)) {
591 Buf->end_index = i;
592 }
593 if( hollerith_count>0 ) { /* fill out implied blanks */
594 hollerith_count -= (max_stmt_col - col + 1);
595 }
596 }
597 /* Skip over leading blank space */
598 else if( ! inside_quote ) {
599 for( ; (c=s[i]) != '\0' && isspace(c); i++, col=PORT_NXTCOL(c,col) ) {
600 continue;
601 }
602 Buf->start_index = i;
603 Buf->start_col = col;
604 }
605
606 /* In fixed form, end_index can fail to get set if line
607 consists of no significant characters other than a
608 continuation mark. This is OK if it is equal to
609 start_index so an EOL will be sent by advance.
610 */
611 Buf->end_index = Buf->start_index;
612
613 /* Now scan rest of line for end of
614 significant text */
615
616 for( ; (c=s[i]) != '\0'; i++, col=PORT_NXTCOL(c,col) ) {
617
618 if( inside_quote ) {
619
620 /* Handle escaped quote. This code does not spot
621 escaped quote split across continuation, but it
622 gets the begin and end markers right anyway.
623 Unix backslash style can't be split since it
624 would escape newline instead.
625 */
626 if( c == quoteChar ) {
627 if( s[i+1] == quoteChar ) {/* escaped quote */
628 i++;
629 col++;
630 }
631 else
632 inside_quote = FALSE;
633 }
634 /* escaped quote via Unix backslash */
635 else if( source_unix_backslash &&
636 c == '\\' && s[i+1] == quoteChar ) {
637 i++;
638 col++;
639 }
640 }
641 else if( c == '\'' || c == '"' ) {
642 inside_quote = TRUE;
643 quoteChar = c;
644 inside_number = FALSE;
645 }
646 /* Not in a quoted string or starting one */
647
648 else {
649 if( isdigit(c) ) { /* number found: see if hollerith */
650 if( inside_number ) { /* this may be a continued number */
651 num_val = num_val*10 + BCD(c);
652 }
653 else {
654 /* hollerith can only follow punctuation */
655 if( ispunct(prev_sig_char) ) {
656 num_val=BCD(c); /* start it off */
657 inside_number = TRUE;
658 }
659 }
660 }
661 if( inside_number ) {
662 if( !(isdigit(c) || isspace(c) || c == INLINE_COMMENT_CHAR) ) {
663 inside_number = FALSE; /* cannot be continued */
664 }
665 if( makeupper(c) == 'H' ) { /* skip past hollerith */
666 Buf->end_index = i; /* the H might be last thing on line */
667 /* We can't just set i = i+num since line may
668 end before then. */
669 i++; col++; /* move past 'H' */
670
671 for(hollerith_count = num_val;
672 (c=s[i]) != '\0' && hollerith_count>0 && col<=max_stmt_col;
673 /* Hmmm: how should tabs in holleriths be counted?
674 As one column or many? We say many. */
675 hollerith_count--, i++, col = PORT_NXTCOL(c,col)) {
676 Buf->end_index = i;
677 }
678 if( hollerith_count>0 ) { /* fill out implied blanks */
679 hollerith_count -= (max_stmt_col - col + 1);
680 }
681 }
682 } /* end of dealing with number and maybe hollerith */
683
684 /* Start of a comment: quit i loop. */
685 if( c == INLINE_COMMENT_CHAR ) {
686 Buf->f90_comment = TRUE;
687 break;
688 }
689
690 } /* end of stuff outside quotes */
691
692 /* Re-test for end of stmt needed here due to
693 advancing i above */
694 if( c == '\0' )
695 break;
696
697 /* As long as interesting stuff is seen,
698 * update end index. This should never
699 * leave end_index undefined since we know line
700 * is not a comment so not all blank.
701 */
702 if( (inside_quote || ! isspace(c)) ) {
703 if( col <= max_stmt_col ) {
704 Buf->end_index = i;
705 prev_sig_char = c;
706 }
707 /* Set up std violation warning if significant
708 chars past std max line length. The second
709 test is to avoid warning if nonsignificant
710 blanks follow end of statement inside quote.
711 */
712 if( col > std_max_stmt_col &&
713 (col <= max_stmt_col || ! isspace(c)) )
714 Buf->overlength = TRUE;
715 }
716 } /* end for i */
717
718 /* A continuation line that is blank except for the
719 continuation mark will leave end_index unchanged
720 from initial -1. This is not illegal in fixed
721 form: f77 std 3.2.3. So we do not treat them
722 as comments, unlike counterpart in freeform.
723 */
724 if( Buf->contin && Buf->end_index == -1 ) {
725 Buf->empty_contin = TRUE;
726 }
727
728 } /* end else not comment */
729 Buf = Buf->next;
730 } /* end while Buf */
731 if(tab_count > 0 && tab_filename == NULL)
732 tab_filename = current_filename; /* for portability warning */
733 }/*find_fixed_contins*/
734
735
736 /* Function to see if line is blank (under freeform rules) */
737 PRIVATE int
line_is_blank(char * s)738 line_is_blank(char *s)
739 {
740 int i, c;
741 for(i=0; (c=s[i]) != '\0' && isspace(c); i++)
742 continue;
743 return (c == '\0');
744 }
745
746