Annotation of freem/src/routine.c, revision 1.10
1.1 snw 1: /*
1.10 ! snw 2: * $Id: routine.c,v 1.9 2025/04/30 20:03:09 snw Exp $
1.1 snw 3: * Routine buffer management
4: *
5: *
1.2 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.3 snw 8: * Copyright (C) 2023, 2025 Coherent Logic Development LLC
1.1 snw 9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
1.4 snw 26: * $Log: routine.c,v $
1.10 ! snw 27: * Revision 1.9 2025/04/30 20:03:09 snw
! 28: * Work on entryref parser
! 29: *
1.9 snw 30: * Revision 1.8 2025/04/30 17:19:16 snw
31: * Improve backtraces in debugger
32: *
1.8 snw 33: * Revision 1.7 2025/04/30 14:41:03 snw
34: * Further debugger work
35: *
1.7 snw 36: * Revision 1.6 2025/04/13 04:22:43 snw
37: * Fix snprintf calls
38: *
1.6 snw 39: * Revision 1.5 2025/04/09 19:52:02 snw
40: * Eliminate as many warnings as possible while building with -Wall
41: *
1.5 snw 42: * Revision 1.4 2025/03/27 03:27:35 snw
43: * Install init scripts to share/freem/examples/init and fix regression in method dispatch
44: *
1.4 snw 45: * Revision 1.3 2025/03/09 19:50:47 snw
46: * Second phase of REUSE compliance and header reformat
47: *
1.3 snw 48: *
49: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
50: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 51: **/
52:
53: #include <string.h>
54: #include <errno.h>
55: #include <sys/types.h>
56:
57: #if !defined(__OpenBSD__) && !defined(__FreeBSD__)
58: # include <sys/timeb.h>
59: #endif
60:
61: #include <sys/ioctl.h>
62: #include <unistd.h>
63: #include <stdlib.h>
64: #include <ctype.h>
65:
66: #ifdef AMIGA68K
67: #include <sys/fcntl.h>
68: #endif
69:
70: #include "mpsdef.h"
71:
72: #include <time.h>
73:
74: #ifdef USE_SYS_TIME_H
75: #include <sys/time.h>
76: #endif
77:
78: #include "events.h"
79:
80: short rtn_get_offset(char *buf)
81: {
82: char *rp;
83: char *rc;
84: char *p;
85: char otag[256];
86: char ortn[256];
87: char oline[256];
88:
89: register int i = 0;
90: register int j = 0;
91: register int k = 0;
92:
93: int os = 0;
94:
95: stcpy (ortn, rou_name);
96:
97: rp = rouptr;
98: rc = roucur;
99:
100: stcnv_m2c (ortn);
101:
102: while (rp < rc) {
103:
104: i = 0;
105: for (p = rp + 1; p < rc && *p != EOL && *p != '\0'; p++) {
106: if (i < 256) {
107: oline[i++] = *p;
108: }
109: }
110: oline[i] = '\0';
111:
112: if (isalpha (oline[0]) || oline[0] == '%') {
113:
114: os = 0;
115: k = 0;
116:
117: for (j = 0; j < strlen (oline); j++) {
118:
119: switch (oline[j]) {
120:
121: case ' ':
122: case '(':
123: case ';':
124: case EOL:
125: otag[k] = '\0';
126:
127: break;
128:
129: default:
130: otag[k++] = oline[j];
131: }
132:
133: if (oline[j] == ' ' || oline[j] == '(' || oline[j] == ';' || oline[j] == EOL) break;
134: }
135: }
136: else {
137: os++;
138: }
139:
140: rp = p + 1;
141: }
142:
143: if (os) {
144: sprintf (buf, "%s+%d^%s\201", otag, os, ortn);
145: }
146: else {
147: sprintf (buf, "%s^%s\201", otag, ortn);
148: }
149:
150:
151: return TRUE;
152: }
153:
154: char *rtn_resolve(char *rou, char *tag, char *buf)
155: {
156: char superclass[255];
157:
158: if (rtn_has_tag (rou, tag)) {
159: strcpy (buf, rou);
160: return buf;
161: }
162: else {
163: if (rtn_get_superclass (rou, superclass)) {
164: return rtn_resolve (superclass, tag, buf);
165: }
166: else {
167: buf = NULL;
168: return NULL;
169: }
170: }
171:
172: }
173:
174: short rtn_get_superclass(char *rou, char *buf)
175: {
176: FILE *fp;
177: char pth[PATHLEN];
178: char line[255];
179: char *s;
180: short rtn_exists;
181: short after_parens;
182: short found_super;
183: char *p;
184: register char ch;
185:
186: if (strcmp (rou, "%OBJECT") == 0) {
187: buf = NULL;
188: return FALSE;
189: }
190:
191: rtn_exists = rtn_get_path (rou, pth);
192:
193: if (rtn_exists == FALSE) {
194: buf = NULL;
195: return FALSE;
196: }
197:
198: fp = fopen (pth, "r");
199: if (fp == NULL) {
200: buf = NULL;
201: return FALSE;
202: }
203:
204: s = fgets (line, 255, fp);
205:
206: fclose (fp);
207:
208: if (s == NULL) {
209: buf = NULL;
210: return FALSE;
211: }
212:
213: if ((!isalpha (line[0])) && (line[0] != '%')) {
214: buf = NULL;
215: return FALSE;
216: }
217:
218: p = line;
219: after_parens = FALSE;
220: found_super = FALSE;
221:
222: while ((ch = *p++) != '\0') {
223:
224: if (ch == ')') after_parens = TRUE;
225:
1.4 snw 226: /* ignore comments in search for superclass */
227: if (ch == ';' && after_parens == TRUE) {
228: found_super = FALSE;
229: break;
230: }
231:
1.1 snw 232: if (ch == ':' && after_parens == TRUE) {
233: strcpy (buf, p);
234: found_super = TRUE;
235: break;
236: }
237:
238: }
239:
240: if (!found_super) {
241: sprintf (buf, "%%OBJECT");
242: return TRUE;
243: }
244:
245: p = buf;
246: for (;;) {
247: ch = *p;
248:
249: if (ch == SP || ch == TAB || ch == ';' || ch == '\0' || ch == '\r' || ch == '\n') {
250: *p = '\0';
251: break;
252: }
253:
254: p++;
255: }
256:
257: return TRUE;
258: }
259:
260: short rtn_get_path(char *rou, char *buf)
261: {
262: FILE *fp;
263: char pth[PATHLEN];
264:
265: if (rou[0] == '%') {
266: stcpy (pth, rou0plib);
267: stcnv_m2c (pth);
268: }
269: else {
270: stcpy (pth, rou0path);
271: stcnv_m2c (pth);
272: }
273:
1.6 snw 274: snprintf (buf, PATHLEN - 1, "%s/%s.m", pth, rou);
1.4 snw 275:
1.1 snw 276: if ((fp = fopen (buf, "r")) != NULL) {
277: (void) fclose (fp);
278:
279: return TRUE;
280: }
281: else {
282: return FALSE;
283: }
284:
285: }
286:
287: short rtn_has_tag(char *rou, char *tag)
288: {
289: m_entry *entries;
290: m_entry *e;
291:
292: entries = rtn_get_entries (rou);
293:
294: for (e = entries; e != NULL; e = e->next) {
295: if (strcmp (tag, e->tag) == 0) {
296: rtn_free_entries (entries);
297: return TRUE;
298: }
299: }
300:
301: rtn_free_entries (entries);
302: return FALSE;
303: }
304:
305: void rtn_free_entries(m_entry *head)
306: {
307: m_entry *tmp;
308:
309: while (head != NULL) {
310: tmp = head;
311: head = head->next;
312: free (tmp);
313: }
314:
315: head = NULL;
316: }
317:
318: m_entry *rtn_get_entries(char *rou)
319: {
320: FILE *fp;
321: char rou_path[PATHLEN];
322: m_entry *head = NULL;
323: m_entry *t;
324: register char ch;
325: register int i = 0;
326: register int j = 0;
327: char cur_line[255];
328: char cur_label[255];
329: int has_args = 0;
330: char *paren_pos;
331:
332: if (rtn_get_path (rou, rou_path) == FALSE) {
333: return (m_entry *) NULL;
334: }
335:
336: fp = fopen (rou_path, "r");
337:
338: while (fgets (cur_line, 255, fp) != NULL) {
339:
340: if (isalpha (cur_line[0]) || cur_line[0] == '%') {
341: has_args = 0;
342: j = 0;
343:
344: for (i = 0; i < strlen (cur_line); i++) {
345: ch = cur_line[i];
346:
347: switch (ch) {
348:
349: case ')':
350: cur_label[j++] = ')';
351:
352: case SP:
353: case TAB:
354: case EOL:
355: cur_label[j] = '\0';
356: j = 0;
357: if (strlen (cur_label)) {
358: t = (m_entry *) malloc (sizeof (m_entry));
359: NULLPTRCHK(t,"rtn_get_entries");
360:
361: paren_pos = strchr (cur_label, '(');
362: if (paren_pos == NULL) {
363: /* not a formallist */
364: t->tag = (char *) malloc (sizeof (char) * (strlen (cur_label) + 1));
365: NULLPTRCHK(t->tag,"rtn_get_entries");
366:
367: strcpy (t->tag, cur_label);
368: }
369: else {
370: /* a formallist */
371: char *toktmp;
372:
373: toktmp = strdup (cur_label);
374: NULLPTRCHK(toktmp,"rtn_get_entries");
375:
376: (void) strtok (toktmp, "(");
377:
378: t->tag = malloc (sizeof (char) * (strlen (toktmp) + 1));
379: NULLPTRCHK(t->tag,"rtn_get_entries");
380:
381: strcpy (t->tag, toktmp);
382:
383: free (toktmp);
384: }
385:
386: t->next = head;
387: head = t;
388: }
389: break;
390:
391: case '(':
392: has_args++;
393: default:
394: cur_label[j++] = ch;
395: }
396:
397: if (ch == SP || ch == TAB || ch == EOL) break;
398: }
399: }
400: }
401:
402: fclose (fp);
403: return head;
404:
405: }
406:
407: void zload (char *rou) /* load routine in buffer */
408: {
409: FILE *infile;
410: short linelen;
411: char pgm[256];
412: char tmp1[256];
413:
414: register long int i;
415: register long int j;
416: register long int ch;
417:
418: char *savptr; /* save routine pointer */
419: long timex;
420: short altern = 0;
421:
422: /* Routines are stored in routine buffers. If a routine is called
423: * we first look whether it's already loaded. If not, we look for
424: * the least recently used buffer and load it there. Besides
425: * dramatically improved performance there is little effect on
426: * the user. Sometimes you see an effect: if the program is changed
427: * by some other user or by yourself using the 'ced' editor you
428: * may get the old version for some time with DO, GOTO or ZLOAD.
429: * A ZREMOVE makes sure the routine is loaded from disk.
430: */
431: if (*rou == EOL || *rou == 0) { /* routine name empty */
432:
433: pgms[0][0] = EOL;
434: rouend = rouins = rouptr = buff;
435: roucur = buff + (NO_OF_RBUF * PSIZE0 + 1);
436:
437: *rouptr = EOL;
438: *(rouptr + 1) = EOL;
439: *(rouptr + 2) = EOL;
440:
441: dosave[0] = 0;
442:
443: return;
444:
445: }
446:
447: savptr = rouptr;
448:
449: /* what time is it ? */
450: timex = time (0L);
451:
452: /* FreeM: it takes a lickin' and keeps on tickin' */
453:
454: /* let's have a look whether we already have the stuff */
455: for (i = 0; i < NO_OF_RBUF; i++) {
456:
457: if (pgms[i][0] == 0) {
458: altern = i;
459: break;
460: } /* buffer empty */
461:
462: j = 0;
463:
464: while (rou[j] == pgms[i][j]) {
465:
466: if (rou[j++] == EOL) {
467:
468: rouptr = buff + (i * PSIZE0);
469: ages[i] = time (0L);
470: rouend = ends[i];
471: rouins = rouend - 1;
472:
473: return;
474:
475: }
476:
477: }
478:
479: if (ages[i] <= timex) timex = ages[altern = i];
480:
481: }
482:
483: /* clear DO-label stored under FOR */
484: dosave[0] = 0;
485: j = 0;
486: ch = EOL; /* init for multiple path search */
487: tmp1[0] = EOL;
488:
489:
490: nextpath: /* entry point for retry */
491:
492: i = 0;
493:
494: if (rou[0] == '%') { /* %_routines are in special directory */
495:
496: if (mcmnd >= 'a') { /* DO GOTO JOB */
497:
498: if (rou0plib[j] != EOL) {
499: while ((ch = pgm[i++] = rou0plib[j++]) != ':' && ch != EOL);
500: }
501:
502: }
503: else if (rou1plib[j] != EOL) {
504: while ((ch = pgm[i++] = rou1plib[j++]) != ':' && ch != EOL);
505: }
506:
507: }
508: else {
509:
510: if (mcmnd >= 'a') { /* DO GOTO JOB */
511:
512: if (rou0path[j] != EOL) {
513: while ((ch = pgm[i++] = rou0path[j++]) != ':' && ch != EOL);
514: }
515:
516: }
517: else if (rou1path[j] != EOL) {
518: while ((ch = pgm[i++] = rou1path[j++]) != ':' && ch != EOL);
519: }
520:
521: }
522:
523: if (i > 0) {
524:
525: if (i == 1 || (i == 2 && pgm[0] == '.')) {
526: i = 0;
527: }
528: else {
529: pgm[i - 1] = '/';
530: }
531:
532: }
533:
534: pgm[i] = EOL;
535:
536: stcpy (tmp1, pgm); /* directory where we search for the routine */
537: stcpy (&pgm[i], rou);
538:
539: rouptr = buff + (altern * PSIZE0);
540:
541: stcat (pgm, rou_ext);
542:
543: pgm[stlen (pgm)] = NUL; /* append routine extension */
544:
545: if ((infile = fopen (pgm, "r")) == NULL) {
546:
547: rouptr = savptr;
548:
549: if (ch != EOL) goto nextpath; /* try next access path */
550:
551: stcpy (varerr, rou);
552:
553: merr_raise (NOPGM);
554:
555: return;
556:
557: }
558:
559: again:
560:
561: linelen = 0;
562: savptr = rouend = rouptr;
563:
564: for (i = 1; i < (PSIZE0 - 1); i++) {
565:
566: *++rouend = ch = getc (infile);
567:
568: if (ch == LF || ch == EOF) {
569:
570: *rouend++ = EOL;
571: i++;
572: *savptr = i - linelen - 2;
573:
574: savptr = rouend;
575: linelen = i;
576:
577: if (ch == EOF) {
578:
579: fclose (infile);
580:
581: *rouend-- = EOL;
582: rouins = rouend - 1;
583: ends[altern] = rouend;
584: ages[altern] = time (0L);
585:
586: stcpy (pgms[altern], rou);
587: stcpy (path[altern], tmp1);
588:
589: rbuf_flags[altern].dialect = standard;
590: if (standard == D_FREEM) {
591: rbuf_flags[altern].standard = FALSE;
592: }
593: else {
594: rbuf_flags[altern].standard = TRUE;
595: }
596:
597: return;
598: }
599: }
600: }
601:
602: rouptr = savptr;
603:
604: if (autorsize) {
605:
606: while ((ch = getc (infile)) != EOF) {
607:
608: i++;
609:
610: if (ch == LF) i++;
611:
612: } /* how big? */
613:
614: i = ((i + 3) & ~01777) + 02000; /* round for full kB; */
615:
616: if (newrsize (i, NO_OF_RBUF) == 0) { /* try to get more routine space. */
617:
618: altern = 0;
619: ch = EOL;
620:
621: fseek (infile, 0L, 0);
622:
623: goto again;
624:
625: }
626:
627: }
628:
629: fclose (infile);
630:
631: goto pgmov;
632:
633: pgmov:
634:
635: /* program overflow error */
636: rouptr = rouins = rouend = savptr;
637: (*savptr++) = EOL;
638: *savptr = EOL;
639:
640: for (i = 0; i < NO_OF_RBUF; i++) {
641: ages[i] = 0;
642: pgms[i][0] = 0;
643: }
644:
645: pgms[i][0] = EOL;
646: rou_name[0] = EOL;
647: merr_raise (PGMOV);
648:
649: return;
650:
651: } /* end of zload() */
652:
653: void zsave (char *rou) /* save routine on disk */
654: {
655: register int i;
656: register int j;
657: register int ch;
658: char tmp[256];
659:
660: stcpy (tmp, rou); /* save name without path */
661:
662: /* look whether we know where the routine came from */
663:
664: if (zsavestrategy) { /* VIEW 133: remember ZLOAD directory on ZSAVE */
665:
666: for (i = 0; i < NO_OF_RBUF; i++) {
667:
668: if (pgms[i][0] == 0) break; /* buffer empty */
669:
670: j = 0;
671:
672: while (rou[j] == pgms[i][j]) {
673:
674: if (rou[j++] == EOL) {
675:
676: stcpy (rou, path[i]);
677: stcat (rou, tmp);
678:
679: j = 0;
680: ch = 1; /* init for multiple path search */
681:
682: goto try;
683:
684: }
685:
686: }
687:
688: }
689:
690: }
691:
692: /* not found */
693: j = 0;
694: ch = EOL; /* init for multiple path search */
695:
696:
697: nextpath: /* entry point for retry */
698:
699: if (tmp[0] == '%') {
700:
701: if (rou1plib[0] != EOL) {
702:
703: i = 0;
704:
705: while ((ch = rou[i++] = rou1plib[j++]) != ':' && ch != EOL);
706:
707: if (i == 1 || (i == 2 && rou[0] == '.')) {
708: i = 0;
709: }
710: else {
711: rou[i - 1] = '/';
712: }
713:
714: stcpy (&rou[i], tmp);
715:
716: }
717:
718: }
719: else {
720:
721: if (rou1path[0] != EOL) {
722:
723: i = 0;
724:
725: while ((ch = rou[i++] = rou1path[j++]) != ':' && ch != EOL);
726:
727: if (i == 1 || (i == 2 && rou[0] == '.')) {
728: i = 0;
729: }
730: else {
731: rou[i - 1] = '/';
732: }
733:
734: stcpy (&rou[i], tmp);
735:
736: }
737:
738: }
739:
740:
741: try:
742:
743: stcat (rou, rou_ext);
744: rou[stlen (rou)] = NUL; /* append routine extention */
745:
746: if (rouend <= rouptr) {
747: unlink (rou);
748: rou_name[0] = EOL;
749: }
750: else {
751: FILE *outfile;
752: char *i0;
753:
754: for (;;) {
755:
756: errno = 0;
757:
758: if ((outfile = fopen (rou, "w")) != NULL) break;
759:
760: if (errno == EINTR) continue; /* interrupt */
761:
762: if (errno == EMFILE || errno == ENFILE) {
763: close_all_globals ();
764: continue;
765: } /* free file_des */
766:
767: if (ch != EOL) goto nextpath; /* try next access path */
768:
769: merr_raise (PROTECT);
770: return;
771:
772: }
773:
774: i0 = rouptr;
775:
776: while (++i0 < (rouend - 1)) {
777:
778: if ((ch = (*(i0))) == EOL) {
779: ch = LF;
780: i0++;
781: }
782:
783: putc (ch, outfile);
784:
785: }
786:
787: if (ch != LF) putc (LF, outfile);
788:
789: fclose (outfile);
790:
791: }
792:
793: return;
794:
795: } /* end of zsave() */
796:
797: /* insert 'line' in routine at 'position' */
798: void zi (char *line, char *position)
799: {
800: short offset;
801: short label;
802: short i;
803: short i0;
804: short ch;
805: char *reg;
806: char *end;
807: char line0[256];
808:
809: if (rouend - rouptr + stlen (line) + 1 > PSIZE0) { /* sufficient space ??? */
810:
811: reg = buff;
812:
813: if (getrmore () == 0L) return; /* PGMOV */
814:
815: position += buff - reg;
816:
817: }
818:
819: label = TRUE;
820: i = 0;
821: i0 = 0;
822:
823: while ((ch = line[i]) != EOL) {
824:
825: if (label) {
826:
827: if (ch == SP) ch = TAB;
828:
829: if (ch == TAB) {
830: label = FALSE;
831: }
832: else if (ch == '(') {
833:
834: line0[i0++] = ch;
835: i++;
836:
837: while (((ch = line[i]) >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '%' || ch == ',') {
838: line0[i0++] = ch;
839: i++;
840: }
841:
842: if (ch != ')') {
843: merr_raise (ISYNTX);
844: return;
845: }
846:
847: line0[i0++] = ch;
848: i++;
849:
850: if ((ch = line[i]) != SP && ch != TAB) {
851: merr_raise (ISYNTX);
852: return;
853: }
854:
855: continue;
856:
857: }
858: else if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && (ch != '%' || i)) {
859: merr_raise (ISYNTX);
860: return;
861: }
862:
863: line0[i0++] = ch;
864: i++;
865:
866: continue;
867:
868: }
869:
870: if (ch < SP || (ch >= DEL && (eightbit == FALSE))) {
871: merr_raise (ISYNTX);
872: return;
873: }
874:
875: line0[i0++] = ch;
876: i++;
877:
878: }
879:
880: if (label) {
881: merr_raise (ISYNTX);
882: return;
883: }
884:
885: line0[i0] = EOL;
886: offset = i0;
887:
888: if (offset > 0) {
889:
890: offset += 2;
891: end = rouend;
892: rouend += offset;
893:
894: if (roucur > position || roucur > end) roucur += offset;
895:
896: reg = rouend;
897:
898: while (position <= end) {
899: (*reg--) = (*end--);
900: }
901:
902: (*(position++)) = (UNSIGN (offset) - 2);
903:
904: reg = line0;
905:
906: while (((*(position++)) = (*(reg++))) != EOL);
907:
908: *(rouend + 1) = EOL;
909: *(rouend + 2) = EOL;
910:
911: for (i = 0; i < NO_OF_RBUF; i++) {
912:
913: if (rouptr == (buff + (i * PSIZE0))) {
914: ends[i] = rouend;
915: break;
916: }
917:
918: }
919:
920: }
921:
922: rouins = position;
923:
924: return;
925: } /* end of zi() */
926:
927: /*
928: * getraddress(char *a, short lvl):
929: *
930: * returns the 'canonical' address of the line at the specified DO/FOR/XEC level
931: *
932: * char *a (out param): pointer to the address of the line
933: * short lvl: process this level
934: *
935: */
936: void getraddress (char *a, short lvl)
937: {
938:
939: char *rcur; /* cursor into routine */
940: short f;
941: char tmp3[256];
942: char *j0;
943: char *j1;
944: short rlvl; /* lower level, where to find routine name */
945: register int i;
946: register int j;
947:
948: f = mcmnd;
949: mcmnd = 'd'; /* make load use standard-path */
950: rlvl = lvl;
951:
952: if (nestn[rlvl] == 0 && rlvl < nstx) rlvl++;
953:
954: if (nestn[rlvl]) zload (nestn[rlvl]);
955:
956: mcmnd = f;
957:
958: /* command on stack: 2 == DO_BLOCK; other: make uppercase */
959: i = nestc[lvl];
960:
961: if (i != '$') i = ((i == 2) ? 'd' : i - 32);
962:
963: a[0] = '(';
964: a[1] = i;
965: a[2] = ')';
966: a[3] = EOL; /* command */
967:
968: rcur = nestr[lvl] + rouptr; /* restore rcur */
969: j0 = (rouptr - 1);
970: j = 0;
971: tmp3[0] = EOL;
972:
973: j0++;
974:
975: if (rcur < rouend) {
976:
977: while (j0 < (rcur - 1)) {
978:
979: j1 = j0++;
980: j++;
981:
982: if ((*j0 != TAB) && (*j0 != SP)) {
983:
984: j = 0;
985:
986: while ((tmp3[j] = (*(j0++))) > SP) {
987:
988: if (tmp3[j] == '(') tmp3[j] = EOL;
989:
990: j++;
991:
992: }
993:
994: tmp3[j] = EOL;
995: j = 0;
996:
997: }
998:
999: j0 = j1;
1000: j0 += (UNSIGN (*j1)) + 2;
1001:
1002: }
1003:
1004: }
1005:
1006: stcat (a, tmp3);
1007:
1008: if (j > 0) {
1009:
1010: i = stlen (a);
1011: a[i++] = '+';
1012:
1013: intstr (&a[i], j);
1014:
1015: }
1016:
1017: if (nestn[rlvl]) {
1018:
1019: stcat (a, "^\201");
1020: stcat (a, nestn[rlvl]);
1021:
1022: }
1023: else if (rou_name[0] != EOL) {
1024:
1025: stcat (a, "^\201");
1026: stcat (a, rou_name);
1027:
1028: }
1029:
1030: f = mcmnd;
1031: mcmnd = 'd'; /* make load use standard-path */
1032:
1033: zload (rou_name);
1034:
1035: mcmnd = f;
1036:
1037: return;
1038:
1039: } /* end getraddress() */
1040:
1041: /* parse lineref and return pos.in routine */
1042: /* result: [pointer to] pointer to line */
1043: void lineref (char **adrr)
1044: {
1045: long offset;
1046: long j;
1047: char *reg;
1048: char *beg;
1049:
1050: while (*codptr == '@') { /* handle indirection */
1051:
1052: codptr++;
1053:
1054: expr (ARGIND);
1055:
1056: if (merr () > 0) return;
1057:
1058: stcat (argptr, codptr);
1059: stcpy (code, argptr);
1060:
1061: codptr = code;
1062:
1063: }
1064:
1065: offset = 0;
1066: beg = rouptr;
1067:
1068: if (*codptr == '+') {
1069:
1070: codptr++;
1071:
1072: expr (STRING);
1073:
1074: if (merr () > 0) return;
1075:
1076: if ((offset = intexpr (argptr)) <= 0) {
1077: *adrr = 0;
1078: return;
1079: }
1080:
1081: offset--;
1082:
1083: }
1084: else {
1085:
1086: expr (LABEL);
1087:
1088: if (merr () > 0) return;
1089:
1090: reg = beg;
1091:
1092: while (beg < rouend) {
1093:
1094: reg++;
1095:
1096: if ((*reg) != TAB && (*reg) != SP) {
1097:
1098: j = 0;
1099:
1100: while ((*reg) == varnam[j]) {
1101: reg++;
1102: j++;
1103: }
1104:
1105: if (((*reg) == TAB || (*reg) == SP || (*reg) == '(') && varnam[j] == EOL) break;
1106:
1107: }
1108:
1109: reg = (beg = beg + UNSIGN (*beg) + 2);
1110:
1111: }
1112:
1113: stcpy (varerr, varnam);
1114:
1115: varnam[0] = EOL;
1116: codptr++;
1117:
1118: if (*codptr == '+') {
1119:
1120: codptr++;
1121:
1122: expr (STRING);
1123:
1124: if (merr () > 0) return;
1125:
1126: offset = intexpr (argptr);
1127:
1128: }
1129:
1130: }
1131:
1132: if (offset < 0) {
1133:
1134: reg = rouptr;
1135:
1136: while (reg < beg) {
1137: reg += UNSIGN (*reg) + 2;
1138: offset++;
1139: }
1140:
1141: if (offset < 0) {
1142: *adrr = 0;
1143: return;
1144: }
1145:
1146: beg = rouptr;
1147:
1148: }
1149:
1150: while (offset-- > 0 && beg <= rouend) beg += UNSIGN (*beg) + 2;
1151:
1152: *adrr = beg;
1153:
1154: return;
1155: } /* end of lineref() */
1.7 snw 1156:
1.8 snw 1157: char *m_text(char *lref, char *buf)
1158: {
1159: char *old_codptr;
1160: char old_code[STRLEN];
1161:
1162: old_codptr = codptr;
1163: stcpy (old_code, code);
1164:
1165: sprintf (code, "$TEXT(%s)\201", lref);
1166: codptr = code;
1167:
1168: expr (STRING);
1169:
1170: if (merr () != OK) {
1171: stcpy (code, old_code);
1172: codptr = old_codptr;
1173: return (char *) NULL;
1174: }
1175:
1176: stcpy (buf, argptr);
1177: stcpy (code, old_code);
1178: codptr = old_codptr;
1179:
1180: return buf;
1181: }
1182:
1183:
1.9 snw 1184:
1185: /* routine_get_line()
1186: * char *entryref: [cstr/in] M entryref
1187: * char *buf: [cstr/out] buffer to contain resulting line
1188: *
1189: * returns a pointer to buf [cstr] on success; otherwise NULL */
1190: char *routine_get_line(char *entryref, char *buf)
1.7 snw 1191: {
1.10 ! snw 1192: FILE *fp;
! 1193: char routine_path[PATHLEN];
! 1194:
1.9 snw 1195: char *routine_p;
1196: char *label_p;
1197: char *offset_p;
1198:
1199: short have_label = FALSE;
1200: short have_offset = FALSE;
1201:
1202: char r[256];
1203: char l[256];
1204: char o[256];
1.10 ! snw 1205: char txtbuf[256];
! 1206: char line[2048];
! 1207: int curline;
! 1208: char curtag[256];
! 1209: int cur_offset;
1.9 snw 1210: int os;
1.10 ! snw 1211:
! 1212: register int i;
! 1213: register int j;
! 1214: char ch;
! 1215:
! 1216: short in_tag = FALSE;
1.9 snw 1217:
1218: /*
1219: * entryref can be:
1220: * +0 (returns rou_name)
1221: * label
1222: * ^routine
1223: * +offset
1224: * +offset^routine
1225: * label^routine
1226: * label+offset^routine
1227: */
1228:
1229: /* handle +0 */
1230: if (strcmp (entryref, "+0") == 0) {
1231: stcpy (buf, rou_name);
1232: stcnv_m2c (buf);
1233: return buf;
1234: }
1235:
1236: if ((routine_p = strchr (entryref, '^')) != NULL) {
1237: /* have a routine */
1238: stcpy (r, routine_p);
1.10 ! snw 1239: stcnv_m2c (r);
! 1240:
! 1241: if ((entryref[0] != '^') && (isalpha (entryref[0]))) {
! 1242: /* we have a label */
! 1243: char ch;
! 1244: char *src;
! 1245: char *dst;
! 1246:
! 1247: src = entryref;
! 1248: dst = l;
! 1249:
! 1250: while (((ch = *src++) != '\0') && (ch != '^') && (ch != '+')) {
! 1251: *dst++ = ch;
! 1252: }
! 1253: *dst = '\0';
! 1254: have_label = TRUE;
! 1255: }
1.9 snw 1256: }
1257: else {
1258: /* no routine implies current routine */
1.10 ! snw 1259: stcpy (r, rou_name);
! 1260: stcnv_m2c (r);
! 1261: }
! 1262:
! 1263: if (r[0] == '^') {
! 1264: strcpy (txtbuf, &(r[1]));
! 1265: strcpy (r, txtbuf);
! 1266: }
! 1267:
! 1268: if (rtn_get_path (r, routine_path) == FALSE) {
! 1269: sprintf (buf, "");
! 1270: return NULL;
1.9 snw 1271: }
1272:
1.10 ! snw 1273: if ((fp = fopen (routine_path, "r")) == NULL) {
! 1274: sprintf (buf, "");
! 1275: return NULL;
! 1276: }
! 1277:
1.9 snw 1278: if ((offset_p = strchr (entryref, '+')) != NULL) {
1279: stcpy (o, offset_p + 1);
1280: os = atoi (o);
1.10 ! snw 1281: sprintf (o, "%d\0", os);
1.9 snw 1282: have_offset = TRUE;
1283: }
1284: else {
1285: have_offset = FALSE;
1.10 ! snw 1286: os = 1;
1.9 snw 1287: }
1288:
1.10 ! snw 1289: in_tag = FALSE;
! 1290: cur_offset = 0;
! 1291: while (fgets (line, sizeof (line) - 1, fp) != NULL) {
1.7 snw 1292:
1.10 ! snw 1293: if (!have_label && !have_offset) {
! 1294: strcpy (buf, line);
! 1295: fclose (fp);
! 1296: return buf;
1.7 snw 1297: }
1.10 ! snw 1298:
! 1299: if (isalpha (line[0]) && !isblank (line[0])) {
! 1300: j = 0;
1.7 snw 1301:
1.10 ! snw 1302: for (i = 0; i < strlen (line); i++) {
! 1303: ch = line[i];
1.7 snw 1304:
1.10 ! snw 1305: if ((!isalpha (ch)) && (!isdigit (ch))) {
! 1306: curtag[j] = '\0';
! 1307: cur_offset = 0;
! 1308: if (have_label && (strcmp (curtag, l) == 0)) {
! 1309: in_tag = TRUE;
! 1310: if (!have_offset) {
! 1311: strcpy (buf, line);
! 1312: fclose (fp);
! 1313: return buf;
! 1314: }
! 1315: }
! 1316: else {
! 1317: in_tag = FALSE;
! 1318: }
! 1319: break;
! 1320: }
! 1321: else {
! 1322: curtag[j++] = ch;
! 1323: }
! 1324: }
1.7 snw 1325: }
1.10 ! snw 1326: else {
! 1327: cur_offset++;
1.7 snw 1328:
1.10 ! snw 1329: if (in_tag && (cur_offset == os)) {
! 1330: strcpy (buf, line);
! 1331: fclose (fp);
! 1332: return buf;
1.7 snw 1333: }
1.10 ! snw 1334: }
! 1335:
1.7 snw 1336: }
1337:
1.10 ! snw 1338: fclose (fp);
! 1339: return FALSE;
1.7 snw 1340:
1341: }
1.9 snw 1342:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>