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