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