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