1 /*
2  * $Id: yinput.c,v 1.4 2010-02-15 05:17:57 dhmunro Exp $
3  * Implement Yorick program text reader.
4  */
5 /* Copyright (c) 2005, The Regents of the University of California.
6  * All rights reserved.
7  * This file is part of yorick (http://yorick.sourceforge.net).
8  * Read the accompanying LICENSE file for details.
9  */
10 
11 #include "yio.h"
12 #include "parse.h"
13 #include "hash.h"
14 #include "pstdlib.h"
15 #include "play.h"
16 #include <string.h>
17 
18 #ifndef PATH_SEP_DELIMIT
19 #define PATH_SEP_DELIMIT ":;"
20 #endif
21 
22 extern void YError(const char *msg);
23 extern int yDebugLevel;        /* declared in ydata.h */
24 extern HashTable globalTable;  /* declared in ydata.h */
25 
26 extern char *MakeErrorLine(long lineNumber, const char *filename);
27 
28 extern long YpLineNumber(void);
29 
30 extern void y_on_stdin(char *input_line);
31 
32 /*--------------------------------------------------------------------------*/
33 
34 IncludeFile *ypIncludes= 0;
35 int nYpIncludes= 0;
36 static int maxYpIncludes= 0;
37 
38 char **ypInputs= 0;
39 int nYpInputs= 0;
40 static int maxYpInputs= 0;
41 
42 HashTable sourceTab;
43 long **sourceList= 0;
44 long *lenSourceList= 0;
45 
46 char **ypPrefixes= 0;
47 int nYpPrefixes= 0;
48 static int maxYpPrefixes= 0;
49 
50 static long rememberLine;  /* set in YpNextLine, used in YpStandby */
51 
52 static void ClearPrefixes(void);
53 static void AddPrefix(char *prefix);
54 
55 static void ClearSourceList(const char *name);
56 
57 static int GetNextLine(p_file *file, int context);
58 
59 static long FindSource(long index);
60 extern long ReopenSource(long index, int notExtern, long isrc);
61 
62 extern int y_pending_stdin(void);
63 static void y_add_line(char *line);
64 static void y_remove_line(int reset);
65 typedef struct y_line_t y_line_t;
66 struct y_line_t {
67   y_line_t *next;
68   char *line;
69 };
70 static y_line_t *y_lhead=0, *y_ltail=0;
71 
72 static int yp_chk_hash(p_file *file, int context, char *line);
73 static char *yp_strtok_text = 0;
74 static char *yp_strtok(char *text, char *delim);
75 static char *
yp_strtok(char * text,char * delim)76 yp_strtok(char *text, char *delim)
77 {
78   char *start = 0;
79   int i;
80   if (text) yp_strtok_text = text;
81   if (!yp_strtok_text) return 0;
82   text = yp_strtok_text;
83   /* skip leading delimiters */
84   while (text[0]) {
85     for (i=0 ; delim[i] ; i++) if (text[0]==delim[i]) break;
86     if (!delim[i]) break;
87     text++;
88   }
89   if (!text[0]) {
90     yp_strtok_text = 0;
91     return 0;
92   }
93   start = text;
94   /* the whole point is to skip Windows drive letter */
95   if (text[1]==':' &&
96       ((text[0]>='A' && text[0]<='Z') ||
97        (text[0]>='a' && text[0]<='z'))) text += 2;
98   /* scan until delimiter */
99   while (text[0]) {
100     for (i=0 ; delim[i] ; i++) if (text[0]==delim[i]) break;
101     if (delim[i]) break;
102     text++;
103   }
104   if (!text[0]) {
105     yp_strtok_text = 0;
106   } else {
107     text[0] = '\0';
108     yp_strtok_text = text+1;
109   }
110   return start;
111 }
112 
YpSetPaths(const char * pathlist)113 void YpSetPaths(const char *pathlist)
114 {
115   char *paths= p_strcpy(pathlist);
116   char *token= yp_strtok(paths, PATH_SEP_DELIMIT);
117   char *prefix;
118 
119   ClearPrefixes();
120 
121   /* crack colon-or-space-delimited list of directory pathnames */
122   while (token) {
123     if (YIsDotRelative(token)) prefix= p_strcpy(token);
124     else prefix= YExpandName(token);
125     AddPrefix(prefix);
126     token= yp_strtok((char *)0, PATH_SEP_DELIMIT);
127   }
128 
129   p_free(paths);
130 
131   /* Set yCWD and yHOME if they haven't been initialized.  */
132   if (!yCWD) YSetCWD((char *)0);
133   if (!yHOME) YGetHOME();
134 }
135 
ClearPrefixes(void)136 static void ClearPrefixes(void)
137 {
138   int i, n= nYpPrefixes;
139   char **prefixes= ypPrefixes;
140   nYpPrefixes= 0;
141   for (i=0 ; i<n ; i++) p_free(prefixes[i]);
142   maxYpPrefixes= 0;
143   ypPrefixes= 0;
144   p_free(prefixes);
145 }
146 
AddPrefix(char * prefix)147 static void AddPrefix(char *prefix)
148 {
149   if (nYpPrefixes>=maxYpPrefixes) {
150     int newSize= maxYpPrefixes+4;
151     ypPrefixes= p_realloc(ypPrefixes, sizeof(char *)*newSize);
152     maxYpPrefixes= newSize;
153   }
154   YNameToHead(&prefix);
155   ypPrefixes[nYpPrefixes++]= prefix;
156 }
157 
158 /* state for YpError initialized in YpPushInclude */
159 static long prevErrLine;
160 
161 static p_file *PushInclude(const char *filename, int fullparse);
162 
YpPushInclude(const char * filename)163 p_file *YpPushInclude(const char *filename)
164 {
165   return PushInclude(filename, 1);
166 }
167 
168 static p_file *default_on_include(const char *filename, int fullparse);
169 static yon_include_cb *open_include = &default_on_include;
170 /* ARGSUSED */
171 static p_file *
default_on_include(const char * filename,int fullparse)172 default_on_include(const char *filename, int fullparse)
173 {
174   return p_fopen(filename, "r");
175 }
176 
177 yon_include_cb *
ycall_on_include(yon_include_cb * on_include)178 ycall_on_include(yon_include_cb *on_include)
179 {
180   yon_include_cb *old = open_include;
181   open_include = on_include? on_include : &default_on_include;
182   return old;
183 }
184 
PushInclude(const char * filename,int fullparse)185 static p_file *PushInclude(const char *filename, int fullparse)
186 {
187   p_file *file= 0;
188   char *name= 0;
189   long i;
190 
191   if (YIsAbsolute(filename)) {
192     /* absolute pathname doesn't need any prefix */
193     file= open_include(filename, fullparse);
194     if (!file) return 0;
195     name= p_strcpy(filename);
196 
197   } else {
198     char *tmp;
199     for (i=0 ; i<=nYpPrefixes ; i++) {
200       if (i<nYpPrefixes) {
201         tmp= p_strncat(ypPrefixes[i], filename, 0);
202         name= YExpandName(tmp);
203         p_free(tmp);
204       } else {
205         /* this branch is probably a bug --
206          * if . is not on path probably should not find file...
207          * maybe protects against empty path?
208          */
209         name= YExpandName(filename);
210         if (!YIsAbsolute(name)) break;
211       }
212       file= open_include(name, fullparse);
213       if (file) break;
214       p_free(name);
215     }
216     if (!file) return 0;
217   }
218 
219   if (nYpIncludes>=maxYpIncludes) {
220     int newSize= maxYpIncludes+4;
221     ypIncludes= p_realloc(ypIncludes, sizeof(IncludeFile)*newSize);
222     maxYpIncludes= newSize;
223   }
224 
225   if (fullparse) ClearSourceList(name);
226 
227   ypIncludes[nYpIncludes].file= file;
228   ypIncludes[nYpIncludes].filename= name;
229   ypIncludes[nYpIncludes].lastLineRead= 0;
230   ypIncludes[nYpIncludes++].index = -1;
231   prevErrLine= -1;
232   return file;
233 }
234 
235 void
y_push_include(p_file * file,const char * filename)236 y_push_include(p_file *file, const char *filename)
237 {
238   if (nYpIncludes >= maxYpIncludes) {
239     int newSize = maxYpIncludes + 4;
240     ypIncludes = p_realloc(ypIncludes, sizeof(IncludeFile)*newSize);
241     maxYpIncludes = newSize;
242   }
243 
244   ypIncludes[nYpIncludes].file = file;
245   ypIncludes[nYpIncludes].filename = p_strcpy(filename);
246   ypIncludes[nYpIncludes].lastLineRead = 0;
247   ypIncludes[nYpIncludes++].index = -1;
248   prevErrLine= -1;
249 }
250 
251 static int need_endif= 0;
252 
YpClearIncludes(void)253 void YpClearIncludes(void)
254 {
255   need_endif= 0;
256   if (nYpIncludes>0) {
257     do {
258       nYpIncludes--;
259       if (ypIncludes[nYpIncludes].file)
260         p_fclose(ypIncludes[nYpIncludes].file);
261       p_free(ypIncludes[nYpIncludes].filename);
262     } while (nYpIncludes);
263   } else {
264     nYpIncludes= 0;
265   }
266   YaltNextLine= 0;
267   if (nYpInputs>0) do p_free(ypInputs[--nYpInputs]); while (nYpInputs);
268   else nYpInputs= 0;
269 
270   /* also clear pending stdin lines */
271   y_remove_line(1);
272 }
273 
ClearSourceList(const char * name)274 static void ClearSourceList(const char *name)
275 {
276   if (HashFind(&sourceTab, name, 0L)) {
277     p_free(sourceList[hashIndex]);
278     sourceList[hashIndex]= 0;
279     lenSourceList[hashIndex]= 0;
280   }
281 }
282 
283 /* Record the given globTab index in the sourceList.  This index
284    corresponds to either a func definition, a struct definition, or an
285    extern statement outside of any functions.  */
RecordSource(long index)286 long RecordSource(long index)
287 {
288   long isrc = -1;
289   if (nYpIncludes) {
290     long *list, len;
291     if (HashAdd(&sourceTab, ypIncludes[nYpIncludes-1].filename, 0L)) {
292       list = sourceList[hashIndex];
293       len = lenSourceList[hashIndex];
294     } else {
295       HASH_MANAGE(sourceTab, long *, sourceList);
296       HASH_MANAGE(sourceTab, long, lenSourceList);
297       sourceList[hashIndex] = list = 0;
298       lenSourceList[hashIndex] = len = 0;
299     }
300     if (!(len&7))
301       sourceList[hashIndex] = list = p_realloc(list, sizeof(long)*(len+8));
302     list[len++] = index;
303     lenSourceList[hashIndex] = len;
304     isrc = hashIndex;
305   }
306   return isrc;
307 }
308 
YpPush(const char * input)309 void YpPush(const char *input)
310 {
311   if (nYpInputs>=maxYpInputs) {
312     int newSize= maxYpInputs+4;
313     ypInputs= p_realloc(ypInputs, sizeof(char *)*newSize);
314     maxYpInputs= newSize;
315   }
316   ypInputs[nYpInputs++]= p_strcpy(input);
317 }
318 
YpPop(void)319 p_file *YpPop(void)
320 {
321   char *filename;
322   p_file *file;
323   if (nYpInputs<=0) return 0;
324   filename= ypInputs[--nYpInputs];
325   file= YpPushInclude(filename);
326   if (!file) {
327     char *msg;
328     msg= p_strncat("missing include file ", filename, 0);
329     YpError(msg);
330     p_free(msg);
331   }
332   p_free(filename);
333   return file;
334 }
335 
336 /*--------------------------------------------------------------------------*/
337 
338 long ypBeginLine= 0;
339 int ypSkipIncludes= 0;
340 
341 extern int yImpossible;   /* used by YError, task.c */
342 extern char *y_read_prompt;  /* ascio.c */
343 extern int yg_blocking;      /* graph.c */
344 
345 static YgetsLine ypBuffer;
346 
347 char *(*YaltNextLine)(int context)= 0;
348 
GetNextLine(p_file * file,int context)349 static int GetNextLine(p_file *file, int context)
350 {
351   /* assert file!=0 */
352   if (file && (yg_blocking || y_read_prompt)) return 0;
353 
354   if (!Ygets(&ypBuffer, file)) {
355     if (file) {
356       int hadEOF= Yfeof(file);
357       int hadError= Yferror(file);
358       p_fclose(file);
359       ypIncludes[nYpIncludes-1].file= 0;
360       /* Any errors here are serious enough to warrant a panic stop.  */
361       if (hadError)
362         YError("****ABORTING PARSE**** error reading include file");
363       if (!hadEOF)
364         YError("****ABORTING PARSE**** include file not ASCII text");
365     }
366     return 0;                   /* just a normal EOF */
367   }
368   if (nYpIncludes) {
369     long lnum= ++ypIncludes[nYpIncludes-1].lastLineRead;
370     if (context==NL_MAIN || context==NL_NOINPUT) ypBeginLine= lnum;
371   } else {
372     if (context==NL_MAIN || context==NL_NOINPUT) ypBeginLine= 0;
373     else ypBeginLine--;
374   }
375   return 1;
376 }
377 
YpLineNumber(void)378 long YpLineNumber(void)
379 {
380   if (nYpIncludes>0) return ypIncludes[nYpIncludes-1].lastLineRead-1;
381   else return -1;
382 }
383 
384 /* YpStandby returns the file position remembered before the previous
385    line was read by YpNextLine.  */
YpStandby(void)386 long YpStandby(void)
387 {
388   return rememberLine;
389 }
390 
391 extern void yr_reader(char *input_line);
392 extern int ym_dbenter;
393 extern int yp_continue;
394 int yp_continue = 0;
395 extern int yp_did_prompt;
396 
397 static void
y_add_line(char * line)398 y_add_line(char *line)
399 {
400   y_line_t *yline = p_malloc(sizeof(y_line_t));
401   if (yline) {
402     yline->next = 0;
403     yline->line = p_strcpy(line);
404     if (y_ltail) {
405       y_ltail->next = yline;
406       y_ltail = yline;
407     } else {
408       y_lhead = y_ltail = yline;
409     }
410   }
411 }
412 
413 static void
y_remove_line(int reset)414 y_remove_line(int reset)
415 {
416   y_line_t *yline, *next;
417   char *line;
418   while (y_lhead) {
419     yline = y_lhead;
420     next = yline->next;
421     line = yline->line;
422     y_lhead = next;
423     if (next)
424       yline->next = 0;
425     else
426       y_ltail = 0;
427     yline->line = 0;
428     p_free(yline);
429     if (line) p_free(line);
430     if (!reset) break;
431   }
432 }
433 
434 void
y_on_stdin(char * input_line)435 y_on_stdin(char *input_line)
436 {
437   int flag = ym_dbenter;
438   ym_dbenter = yp_did_prompt = 0;
439   if (!y_read_prompt) {
440     if (input_line)
441       while (input_line[0]==' ' || input_line[0]=='\t') input_line++;
442     if (flag && input_line && input_line[0]) {
443       extern void yg_got_expose(void);
444       yp_continue = 0;
445       if (p_signalling) p_abort();
446       /* drop current debug block plus task and clean up vm state */
447       ResetStack(0);
448       yr_reset();
449       yg_got_expose();
450       p_clr_alarm(0, 0);
451     }
452     if (yg_blocking) {
453       if (yg_blocking==2) {
454         extern void yg_got_expose(void);
455         yg_got_expose();  /* escape from pause on keyboard input */
456         if (input_line && input_line[0])
457           YputsErr("WARNING discarding keyboard input that aborts pause");
458         return;
459       } else {
460         YputsErr("WARNING discarding keyboard input during window wait");
461         return;
462       }
463     }
464     y_add_line(input_line);
465   } else {
466     yr_reader(input_line);
467   }
468 }
469 
470 int
y_pending_stdin(void)471 y_pending_stdin(void)
472 {
473   int flag;
474   if (y_lhead) {
475     do {
476       flag = yp_chk_hash(0, yp_continue, y_lhead->line);
477       flag = yp_parse_keybd((flag&1)? 0 : y_lhead->line, !yp_continue);
478       yp_continue = (flag!=0 && flag!=1);
479       y_remove_line(0);
480     } while (y_lhead && yp_continue);
481     return (y_lhead!=0);
482   } else {
483     return 0;
484   }
485 }
486 
487 /* possible results:
488  * 0 -- this line was not #include (or ypSkipIncludes), #if, or #endif
489  *      or was a syntax error
490  * 1 bit means get next line (successful include, #if 1, or #endif)
491  * 2 -- this line was #include, file missing (YpError called)
492  * 3 -- this line was #include, file pushed successfully
493  * 4 -- this line was #if 0, no matching #endif
494  * 5 -- this line was #if 0, skipped past matching #endif (in ypBuffer)
495  * 7 -- this line was #if 1
496  * 9 -- this line was #endif
497  */
498 static int
yp_chk_hash(p_file * file,int context,char * line)499 yp_chk_hash(p_file *file, int context, char *line)
500 {
501   /* Check whether this is an include line or an if line.
502    * Correct format is ([OWS] means optional whitespace characters):
503    * [OWS]#[OWS]include[OWS]"filename"[OWS]
504    * or
505    * [OWS]#[OWS]include[OWS]<filename>[OWS]
506    */
507   while (*line && (*line==' ' || *line=='\t' || *line=='\f')) line++;
508   if (*line=='#' && line[1]) {
509     char *incl= "include";
510     line++;
511     while (*line && (*line==' ' || *line=='\t')) line++;
512     while (*line && *incl && (*line++ == *incl++));
513     if (!*incl && context<NL_CONTINUE) {
514       char delim;
515       if (ypSkipIncludes) return 0;
516       while (*line && (*line==' ' || *line=='\t')) line++;
517       delim= *line;
518       if (delim=='\"' || delim=='<') {
519         char *filename= ++line;
520         if (delim=='<') delim = '>';
521         while (*line && *line!=delim) line++;
522         if (*line && line>filename) {
523           *line++= '\0';  /* 0-terminate filename */
524           while (*line && (*line==' ' || *line=='\t')) line++;
525           if (!*line) {
526             char *msg;
527             if ((file= YpPushInclude(filename))) return 3;
528             msg= p_strncat("missing include file ", filename, 0);
529             YpError(msg);
530             p_free(msg);
531             return 2;
532           }
533         }
534       }
535 
536     } else if (incl[-1]=='n' && line[-1]=='f' &&
537                (line[0]==' ' || line[0]=='\t') && file) {
538       /* this is #if line, maybe should skip to matching #endif */
539       line++;
540       while (*line && (*line==' ' || *line=='\t')) line++;
541       if ((line[0]=='0' || line[0]=='1')
542           && (!line[1] || line[1]==' ' || line[1]=='\t')) {
543         if (line[0]=='0') {
544           int count = 0;
545           for (;;) {
546             if (p_signalling) p_abort();
547             if (!GetNextLine(file, context)) return 4;
548             line = ypBuffer.line;
549             while (*line && (*line==' ' || *line=='\t' || *line=='\f'))
550               line++;
551             if (*line=='#') {
552               line++;
553               while (*line && (*line==' ' || *line=='\t')) line++;
554               if (line[0]=='i' && line[1]=='f' &&
555                   (line[2]==' ' || line[2]=='\t')) {
556                 count++;        /* nested #if (don't bother checking 0) */
557               } else {
558                 char *endi = "endif";
559                 while (*line && *endi && (*line++ == *endi++));
560                 if (!*endi &&
561                     (!line[0] || line[0]==' ' || line[0]=='\t') &&
562                     !count--) return 5;
563               }
564             }
565           }
566         } else {  /* #if 1 */
567           need_endif++;
568           return 7;
569         }
570       }
571 
572     } else if (need_endif && incl[-1]=='i' && line[-1]=='e' &&
573                line[0]=='n' && line[1]=='d' && line[2]=='i' &&
574                line[3]=='f' &&
575                (!line[4] || line[4]==' ' || line[4]=='\t')) {
576       need_endif--;
577       return 9;  /* read line after #endif */
578     }
579   }
580   return 0;
581 }
582 
583 char *
YpNextLine(int context)584 YpNextLine(int context)
585 {
586   p_file *file;
587   char *line;
588 
589   /* In skip-includes mode, remember where each line begins for
590    * use by YpStandby.  */
591   if (ypSkipIncludes && nYpIncludes && ypIncludes[nYpIncludes-1].file)
592     rememberLine = p_ftell(ypIncludes[nYpIncludes-1].file);
593   else
594     rememberLine = -1;
595 
596   /* If there is an alternate input source, use it.  */
597   if (YaltNextLine) {
598     line = YaltNextLine(context);
599     if (!line) YaltNextLine = 0;  /* "close" alternate input source */
600     return line;
601   }
602 
603   /* get the current include file */
604   if (nYpIncludes==0) {
605     file = 0;
606   } else for (;;) {
607     if ((file=ypIncludes[nYpIncludes-1].file)) break;
608     need_endif = 0;
609     p_free(ypIncludes[nYpIncludes-1].filename);
610     if (!(--nYpIncludes)) break;
611   }
612   if (!file && nYpInputs) do file = YpPop(); while (!file && nYpInputs);
613 
614   /* quit if input is not from include file.  */
615   if (!file) return 0;
616 
617   for (;;) {
618     if (p_signalling) p_abort();
619     /* Get an arbitrary (okay, < MAX_LINE) length input line.  */
620     if (!GetNextLine(file, context)) return 0;
621     /* if first line of file begins with #! discard it
622      * (allows yorick source files to be scripts on most UNIX systems) */
623     if (nYpIncludes && ypIncludes[nYpIncludes-1].lastLineRead==1 &&
624         ypBuffer.line[0]=='#' && ypBuffer.line[1]=='!') {
625       if (!GetNextLine(file, context)) return 0;
626     }
627 
628     line = ypBuffer.line;
629     if (line && context<=NL_CONTINUE) {
630       int flag = yp_chk_hash(file, context, line);
631       if (flag&1) {
632         file = ypIncludes[nYpIncludes-1].file;
633         continue;
634       }
635     }
636     break;
637   }
638 
639   yImpossible = 0;  /* tell YError that a line has come in */
640   return line;
641 }
642 
643 /*--------------------------------------------------------------------------*/
644 
645 static char pErrorMsg[128];
646 static char *errorLoc= 0;
647 
648 int ypErrors;        /* error count for most recent call to YpParse */
649 int ypMaxErrors= 16; /* give up after this many */
650 
MakeErrorLine(long lineNumber,const char * filename)651 char *MakeErrorLine(long lineNumber, const char *filename)
652 {
653   char *tmp= errorLoc;
654   errorLoc= 0;
655   p_free(tmp);
656   if (lineNumber<0) pErrorMsg[0]= '\0';
657   else sprintf(pErrorMsg, "  LINE: %ld  FILE: ", lineNumber);
658   errorLoc= p_strncat(pErrorMsg, filename, 0);
659   return errorLoc;
660 }
661 
662 extern int yBatchMode;  /* may be set with -batch, see std0.c */
663 PLUG_API int yerror_flags;  /* see task.c */
664 
YpError(char * msg)665 void YpError(char *msg)
666 {
667   if (ypSkipIncludes) return;  /* this is not a real parse */
668   ypErrors++;
669   strcpy(pErrorMsg, "SYNTAX: ");
670   strncat(pErrorMsg, msg, 110);
671   if (!(yerror_flags&1)) {
672     YputsErr(pErrorMsg);
673     if (nYpIncludes) {
674       long lineNumber= ypIncludes[nYpIncludes-1].lastLineRead;
675       if (lineNumber!=prevErrLine) {
676         char *filename= ypIncludes[nYpIncludes-1].filename;
677         YputsErr(MakeErrorLine(lineNumber, filename));
678         prevErrLine= lineNumber;
679       }
680     }
681   }
682   if (yBatchMode || ypErrors>=ypMaxErrors || (yerror_flags&1)) {
683     ypErrors= 0;
684     if (ypMaxErrors<1) ypMaxErrors= 1;
685     if (yerror_flags&1) YError(pErrorMsg);
686     else YError("****ABORTING PARSE**** too many errors");
687   }
688 }
689 
690 /*--------------------------------------------------------------------------*/
691 
FindSource(long index)692 static long FindSource(long index)
693 {
694   long i, j, len, *list;
695 
696   /* Each source file i has an associated list of indices of the variables
697      which were defined as func, struct, or *main* extern in that source
698      file.  Search them in reverse order of the first time they were
699      included -- note that this probably, but not necessarily, picks up
700      the most recent definition.  This quirk constrains Yorick programming
701      style somewhat -- you can't be as free in reusing a single function
702      name as you might like...  */
703   for (i=sourceTab.nItems-1 ; i>=0 ; i--) {
704     list= sourceList[i];
705     len= lenSourceList[i];
706     /* inner loop is on variables defined in this source file */
707     for (j=len-1 ; j>=0 ; j--) if (list[j]==index) break;
708     if (j>=0) break;
709   }
710 
711   return i;  /* -1 on failure */
712 }
713 
ReopenSource(long index,int notExtern,long isrc)714 long ReopenSource(long index, int notExtern, long isrc)
715 {
716   long source, position;
717   p_file *file;
718 
719   source = (isrc<0)? FindSource(index) : isrc;
720   if (source<0) return -1;    /* source of func unknown */
721 
722   file= PushInclude(sourceTab.names[source], 0);
723   if (!file) return -2;       /* unable to open source file */
724 
725   position= ScanForFunc(globalTable.names[index], notExtern);
726   if (position<0 || p_fseek(file, position)) {
727     if (ypIncludes[nYpIncludes-1].file) {
728       p_fclose(file);
729       ypIncludes[nYpIncludes-1].file= 0;
730     }
731     if (position<0) return -3;  /* func no longer in source file */
732     else return -4;             /* seek error */
733   }
734 
735   return position;
736 }
737 
OpenSource(long index,long isrc)738 p_file *OpenSource(long index, long isrc)
739 {
740   long position= ReopenSource(index, 0, isrc);
741   p_file *file;
742   if (position>=0) {
743     file= ypIncludes[nYpIncludes-1].file;
744     ypIncludes[nYpIncludes-1].file= 0;
745   } else {
746     file= 0;
747   }
748   return file;
749 }
750 
751 /*--------------------------------------------------------------------------*/
752