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