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