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

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

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