Annotation of freem/src/routine.c, revision 1.8

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>