File:  [Coherent Logic Development] / freem / src / global_bltin.c
Revision 1.13: download - view: text, annotated - select for diffs
Wed Apr 9 14:34:30 2025 UTC (11 months, 3 weeks ago) by snw
Branches: MAIN
CVS tags: HEAD
Further work on global_bltin.c refactor

    1: /*
    2:  *   $Id: global_bltin.c,v 1.13 2025/04/09 14:34:30 snw Exp $
    3:  *    freem database engine
    4:  *
    5:  *  
    6:  *   Author: Serena Willis <snw@coherent-logic.com>
    7:  *    Copyright (C) 1998 MUG Deutschland
    8:  *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
    9:  *
   10:  *
   11:  *   This file is part of FreeM.
   12:  *
   13:  *   FreeM is free software: you can redistribute it and/or modify
   14:  *   it under the terms of the GNU Affero Public License as published by
   15:  *   the Free Software Foundation, either version 3 of the License, or
   16:  *   (at your option) any later version.
   17:  *
   18:  *   FreeM is distributed in the hope that it will be useful,
   19:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   20:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   21:  *   GNU Affero Public License for more details.
   22:  *
   23:  *   You should have received a copy of the GNU Affero Public License
   24:  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
   25:  *
   26:  *   $Log: global_bltin.c,v $
   27:  *   Revision 1.13  2025/04/09 14:34:30  snw
   28:  *   Further work on global_bltin.c refactor
   29:  *
   30:  *   Revision 1.12  2025/04/09 00:43:07  snw
   31:  *   Exit with fatal error if a header mismatch found
   32:  *
   33:  *   Revision 1.11  2025/04/08 21:41:13  snw
   34:  *   Make insert, update, and splitp global handler functions take a ptr to a global_handle instead of a file descriptor
   35:  *
   36:  *   Revision 1.10  2025/04/08 20:00:56  snw
   37:  *   Global handler now uses a header file and maintains the last journaling transaction ID
   38:  *
   39:  *   Revision 1.9  2025/04/08 16:46:11  snw
   40:  *   Add global file header and offsets
   41:  *
   42:  *   Revision 1.8  2025/04/08 14:39:21  snw
   43:  *   Initial work on global handler refactor
   44:  *
   45:  *   Revision 1.7  2025/03/24 04:13:11  snw
   46:  *   Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
   47:  *
   48:  *   Revision 1.6  2025/03/24 01:33:30  snw
   49:  *   Guard declaration of time function in global_bltin.c for portability
   50:  *
   51:  *   Revision 1.5  2025/03/22 22:52:24  snw
   52:  *   Add STRLEN_GBL macro to manage global string length
   53:  *
   54:  *   Revision 1.4  2025/03/09 19:14:25  snw
   55:  *   First phase of REUSE compliance and header reformat
   56:  *
   57:  *
   58:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
   59:  * SPDX-License-Identifier: AGPL-3.0-or-later
   60:  **/
   61: 
   62: #include <sys/types.h>
   63: #include <sys/stat.h>
   64: #include <fcntl.h>
   65: #include <unistd.h>
   66: #include <string.h>
   67: #include <stdlib.h>
   68: #include <errno.h>
   69: 
   70: #include "mpsdef.h"
   71: #include "journal.h"
   72: #include "global_bltin.h"
   73: 
   74: global_handle *global_handles_head;
   75: unsigned long gbl_cache_misses = 0;
   76: unsigned long gbl_cache_hits = 0;
   77: 
   78: static void b_free (short filedes, unsigned long blknbr);
   79: static void splitp (global_handle *g, char *block, long *addr, long *offs, unsigned long *blknbr);
   80: static void update (global_handle *g, char *ins_key, long keyl);
   81: static void insert (global_handle *g, char *ins_key, long key_len, unsigned long blknbr);
   82: static void scanpblk (char *block, long *adr, long *fnd);
   83: static void scandblk (char *block, long *adr, long *fnd);
   84: static void getnewblk (int filedes, unsigned long *blknbr);
   85: static short int g_collate (char *t);
   86: //static short int g_numeric (char *str);
   87: short g_numeric (char *str);
   88: void close_all_globals(void);
   89: static void panic (void);
   90: 
   91: #define ROOT 0L
   92: 
   93: /* end of line symbol in global module is 30, which is a code not */
   94: /* otherwise used in subscripts                                   */
   95: #define g_EOL 30
   96: 
   97: #define EOL1 EOL
   98: 
   99: /* numerics (('.'<<1)&037)==28 ; (('-'<<1)&037)==26; */
  100: #define POINT 28
  101: #define MINUS 26
  102: 
  103: /* ALPHA and OMEGA are dummy subscripts in $order processing */
  104: /* ALPHA sorts before all other subscripts                   */
  105: /* OMEGA sorts after all other subscripts                    */
  106: /* e.g. ("abc") -> "abc",OMEGA ; ("abc","") -> "abc",ALPHA   */
  107: #define OMEGA 29
  108: #define ALPHA 31
  109: 
  110: /* length of blocks. status bytes defined as offset to blocklength */
  111: /*      BLOCKLEN 1024           is defined in mpsdef0 include file */
  112: #define DATALIM (BLOCKLEN-11)
  113: #define LLPTR   (BLOCKLEN-10)
  114: #define NRBLK    LLPTR
  115: #define COLLA   (BLOCKLEN- 7)
  116: #define RLPTR   (BLOCKLEN- 6)
  117: #define FREE     RLPTR
  118: #define BTYP    (BLOCKLEN- 3)
  119: #define OFFS    (BLOCKLEN- 2)
  120: 
  121: /* length of blockpointers in bytes */
  122: #define PLEN     3
  123: 
  124: #define EMPTY    0
  125: #define FBLK     1
  126: #define POINTER  2
  127: #define BOTTOM   6
  128: #define DATA     8
  129: 
  130: #if !defined(__OpenBSD__) && !defined(_AIX) && !defined(__osf__) && !defined(MSDOS) && !defined(__vax__) && !defined(__OS2__)
  131:  long time ();
  132: #endif
  133: 
  134: inline long gbl_path(char *key, char *buf)
  135: {
  136:     long savj;
  137:     long savch;			/* saved j and ch for multiple pathes */
  138: 
  139:     register long int i;
  140:     register long int j;
  141:     register long int k;
  142:     register long int ch;
  143:     long pathscan;			/* flag for repeated scan of pathlist setting an undef global */
  144:    
  145:     /* construct full UNIX filename */
  146:     savj = 0;
  147:     savch = ch = EOL;
  148:     pathscan = TRUE;
  149: nextpath:
  150:     k = 0;
  151:     j = savj;
  152: 
  153:     if (key[1] == '%' || key[1] == '$') {		/* %-globals and SSVN backing storage, no explicit path */
  154:         
  155:         if (gloplib[0] != EOL) {
  156:             
  157:             /* append % global access path */
  158:             while ((ch = buf[k++] = gloplib[j++]) != ':' && ch != EOL); 
  159: 
  160:         } 
  161: 
  162:     }
  163:     else if (key[1] != '/') {		/* no explicit path specified */
  164:         
  165:         if (glopath[0] != EOL) {
  166: 
  167:             /* append global access path */
  168:             while ((ch = buf[k++] = glopath[j++]) != ':' && ch != EOL);
  169: 
  170:         }
  171: 
  172:     }
  173: 
  174:     if (savj == 0 && ch == EOL) pathscan = FALSE;		/* one path only: inhibit search */
  175:     
  176:     if (k > 0) {
  177: 
  178:         if (k == 1 || (k == 2 && buf[0] == '.')) {
  179:             k = 0;
  180:         }
  181:         else {
  182:             buf[k - 1] = '/';
  183:         }
  184: 
  185:     }
  186: 
  187:     savch = ch;
  188:     savj = j;
  189:     i = 0;
  190:     j = 0;
  191: 
  192:     while (key[i] != EOL) {
  193: 
  194:         if ((buf[k] = key[i]) == DELIM) break;
  195:         
  196:         if (buf[k] == '/') {
  197:             
  198:             j = i;
  199: 
  200:             if (k > i) {
  201:                 i = 0;
  202:                 j = 0;
  203:                 k = 0;
  204: 
  205:                 continue;
  206:             }
  207: 
  208:         }
  209: 
  210:         i++;
  211:         k++;
  212:     
  213:     }
  214: 
  215:     buf[k] = NUL;			/* NUL not EOL !!! */
  216: 
  217:     return i;
  218: } /* gbl_path() */
  219: 
  220: void gbl_cache_hit(global_handle *g)
  221: {
  222:     g->cache_hits++;
  223:     gbl_cache_hits++;
  224: } /* gbl_cache_hit() */
  225: 
  226: void gbl_cache_miss(global_handle *g)
  227: {
  228:     g->fast_path = 0;
  229:     g->cache_misses++;
  230:     gbl_cache_misses++;
  231: } /* gbl_cache_miss() */
  232: 
  233: int gbl_lock(global_handle *g, int type)
  234: {
  235:     if (g->locked == TRUE || lonelyflag == TRUE) {
  236:         return TRUE;
  237:     }
  238: 
  239:     locking (g->fd, type, 0L);
  240:     g->locked = TRUE;
  241: } /* gbl_lock() */
  242: 
  243: int gbl_unlock(global_handle *g)
  244: {
  245:     if (g->locked == FALSE || lonelyflag == TRUE) {
  246:         return TRUE;
  247:     }
  248: 
  249:     locking (g->fd, 0, 0L);
  250:     g->locked = FALSE;
  251: } /* gbl_unlock() */
  252: 
  253: void gbl_close(global_handle *g)
  254: {
  255:     if (g->opened == TRUE) {
  256:         close (g->fd);
  257: 
  258:         g->use_count = 0;
  259:         g->age = 0;
  260:         g->last_block = 0;
  261:         g->locked = FALSE;
  262:         g->opened = FALSE;
  263:     }
  264: } /* gbl_close() */
  265: 
  266: void gbl_close_all(void)
  267: {
  268:     global_handle *g;
  269: 
  270:     for (g = global_handles_head; g != NULL; g = g->next) {
  271:         gbl_close (g);
  272:     }
  273: } /* gbl_close_all() */
  274: 
  275: int gbl_write_initial_header(global_handle *g)
  276: {
  277:     global_header hdr;
  278:     unsigned long old_position;
  279:     char m[5] = GBL_MAGIC;
  280:     char msg[256];
  281:     
  282:     if (g->opened == FALSE) {
  283:         return FALSE;
  284:     }
  285: 
  286:     memcpy (hdr.magic, m, 5);
  287:     hdr.format_version = GBL_FORMAT_VERSION;
  288:     strncpy (hdr.host_triplet, HOST, 40);
  289:     hdr.block_size = BLOCKLEN;
  290:     hdr.last_transaction_id = 0;
  291:     hdr.created = time (0L);
  292:     hdr.last_backup = -1;
  293:     
  294:     gbl_lock (g, 1);
  295:     old_position = lseek (g->fd, 0, SEEK_CUR);
  296:     lseek (g->fd, 0, SEEK_SET);
  297: 
  298:     if (write (g->fd, &hdr, sizeof (global_header)) == -1) {
  299:         snprintf (msg, sizeof (msg), "error %d writing global header for %s", errno, g->global_name);
  300:         m_fatal (msg);
  301:     }
  302:     
  303:     lseek (g->fd, old_position, SEEK_SET);
  304:     gbl_unlock (g);
  305: 
  306:     return TRUE;
  307: } /* gbl_write_initial_header() */
  308: 
  309: 
  310: int gbl_write_header(global_handle *g, global_header *hdr)
  311: {
  312:     unsigned long old_position;
  313:     char msg[256];
  314:     
  315:     if (g->opened == FALSE) {
  316:         return FALSE;
  317:     }
  318:     
  319:     gbl_lock (g, 1);
  320:     old_position = lseek (g->fd, 0, SEEK_CUR);
  321:     lseek (g->fd, 0, SEEK_SET);
  322: 
  323:     if (write (g->fd, hdr, sizeof (global_header)) == -1) {
  324:         snprintf (msg, sizeof (msg), "error %d writing global header for %s", errno, g->global_name);
  325:         m_fatal (msg);
  326:     }
  327: 
  328:     lseek (g->fd, old_position, SEEK_SET);
  329:     gbl_unlock (g);
  330: 
  331:     gbl_read_header (g, &g->header);
  332:     
  333:     return TRUE;    
  334: } /* gbl_write_header() */
  335: 
  336: int gbl_read_header(global_handle *g, global_header *h)
  337: {
  338:     unsigned long old_position;
  339:     char m[5] = GBL_MAGIC;
  340: 
  341:     
  342:     if (g->opened == FALSE) {
  343:         return GBL_HDR_NOTOPEN;
  344:     }
  345: 
  346:     gbl_lock (g, 1);
  347:     old_position = lseek (g->fd, 0, SEEK_CUR);
  348:     lseek (g->fd, 0, SEEK_SET);
  349: 
  350:     read (g->fd, h, sizeof (global_header));
  351: 
  352:     lseek (g->fd, old_position, SEEK_SET);
  353:     gbl_unlock (g);
  354: 
  355:     if (strncmp (h->magic, m, 5) != 0) {
  356:         return GBL_HDR_BADMAGIC;
  357:     }
  358:     if (h->format_version != GBL_FORMAT_VERSION) {
  359:         return GBL_HDR_BADVERSION;
  360:     }
  361:     if (h->block_size != BLOCKLEN) {
  362:         return GBL_HDR_BADBLOCKSIZE;
  363:     }
  364: 
  365:     return GBL_HDR_OK;                          
  366: } /* gbl_read_header() */
  367: 
  368: int gbl_update_tid(global_handle *g)
  369: {
  370:     global_header h;
  371: 
  372:     if (gbl_read_header (g, &h) != GBL_HDR_OK) {
  373:         return FALSE;
  374:     }
  375: 
  376:     h.last_transaction_id = jnl_tran_id;
  377: 
  378:     return gbl_write_header (g, &h);        
  379: } /* gbl_update_tid() */
  380: 
  381: int gbl_create(global_handle *g)
  382: {
  383:     while (1) {
  384:         errno = 0;
  385: 
  386:         if ((g->fd = creat (g->global_path, 0666)) != -1) break;
  387: 
  388:         if (errno == EMFILE || errno == ENFILE) {
  389:             gbl_close_all ();
  390:             continue;
  391:         }
  392: 
  393:         return PROTECT;
  394:     }
  395: 
  396:     g->opened = TRUE;
  397:     g->age = time (0L);
  398:     g->last_block = 0;
  399:     g->use_count = 1;
  400:     g->fast_path = 0;
  401:     
  402:     gbl_write_initial_header (g);
  403:     
  404:     return OK;
  405: } /* gbl_create() */
  406: 
  407: short gbl_open(global_handle *g, short action)
  408: {
  409:     int result;
  410:     
  411:     if (g->opened == FALSE) {
  412:         gbl_cache_miss (g);
  413:         while (1) {
  414:             errno = 0;
  415:             g->fd = open (g->global_path, 2);
  416:             
  417:             if (g->fd != -1) break;
  418:             
  419:             switch (errno) {            
  420:                 case EINTR:
  421:                     continue;
  422:                     
  423:                 case EMFILE:
  424:                 case ENFILE:
  425:                     gbl_close_all ();
  426:                     continue;
  427:             }
  428:             
  429:             break;
  430:         }
  431:         
  432:         if (g->fd == -1) {
  433:             g->use_count = 0;
  434:             g->age = 0;
  435:             g->last_block = 0;
  436:             g->locked = FALSE;
  437:             g->opened = FALSE;
  438:         }
  439:         else {
  440:             g->opened = TRUE;
  441:             result = gbl_read_header (g, &g->header);
  442:             
  443:             if (result == GBL_HDR_OK) {
  444:                 g->opened = TRUE;
  445:             }
  446:             else {                
  447:                 gbl_close (g);
  448:                 set_io (UNIX);
  449:                 
  450:                 switch (result) {
  451:                     
  452:                     case GBL_HDR_BADMAGIC:
  453:                         fprintf (stderr, "gbl_open:  bad magic value in %s [FATAL]\n", g->global_name);
  454:                         exit (1);
  455:                         break;
  456: 
  457:                     case GBL_HDR_BADVERSION:
  458:                         fprintf (stderr, "gbl_open:  global version is %d in %s (must be %d) [FATAL]\n", g->header.format_version, g->global_name, GBL_FORMAT_VERSION);
  459:                         exit (1);
  460:                         break;
  461: 
  462:                 }
  463:                         
  464:                 return FALSE;
  465:             }
  466:         }
  467:     }
  468: 
  469:     return g->opened;
  470:     
  471: } /* gbl_open() */
  472: 
  473: global_handle *gbl_handle(char *key)
  474: {
  475:     global_handle *g;
  476:     char global_name[256];
  477:     int i;
  478:     long path_len;
  479:     char block[BLOCKLEN];
  480:     struct stat dinf;		 
  481:     
  482:     i = 0;
  483:     while (key[i] != EOL) {
  484:         if ((global_name[i] = key[i]) == DELIM) break;
  485: 
  486:         i++;
  487:     }
  488:     global_name[i] = NUL;
  489: 
  490:     
  491:     for (g = global_handles_head; g != NULL; g = g->next) {
  492:         if (strncmp (g->global_name, global_name, 256) == 0) {
  493:             g->use_count++;
  494:             if (!lonelyflag) {
  495:                 g->fast_path = 0;
  496:             }
  497: 
  498:             fstat (g->fd, &dinf);
  499:             if (g->age > dinf.st_mtime) {
  500:                 g->fast_path = 2;
  501:                 return g;
  502:             }
  503: 
  504:             g->age = time (0L);
  505:             g->fast_path = 0;
  506:             
  507:             return g;
  508:         }
  509:     }
  510:     g = (global_handle *) malloc (sizeof (global_handle));
  511:     NULLPTRCHK(g,"gbl_open");
  512: 
  513:     g->use_count = 1;
  514:     g->locked = FALSE;
  515:     g->age = time (0L);
  516:     g->last_block = 0;
  517:     g->opened = FALSE;
  518:     g->fd = 0;
  519:     g->fast_path = -1;
  520:     g->cache_misses = 0;
  521:     g->cache_hits = 0;
  522:     
  523:     strcpy (g->global_name, global_name);    
  524:     gbl_path (key, g->global_path);
  525:     
  526:     g->next = global_handles_head;
  527:     global_handles_head = g;
  528: 
  529:     return g;    
  530: } /* gbl_handle() */
  531: 
  532: 
  533: /* globals management */
  534:     
  535: /* 0 = set_sym      1 = get_sym */
  536: /* 2 = kill_sym     3 = $data   */
  537: /*                  5 = $fra_order  */
  538: /*                  7 = $fra_query  */
  539: /*                              */
  540: /* 14=killone       13=getnext  */
  541: /* 16=merge_sym     17=$zdata   */
  542: /* gvn as ASCII-string */
  543: 
  544: /* returns      OK      action fulfilled        */
  545: /* (ierr)       UNDEF   missing in action       */
  546: /*              NAKED   illegal naked reference */
  547: /*              SBSCR   illegal subscript       */
  548: /*              DBDGD   data base degradation   */
  549: 
  550: /* The data is organized in a B* tree structure on external storage.
  551:  * For a description of the principles of the algorithms see
  552:  * Donald E. Knuth "The Art of Computer Programming" vol. 3 p. 478.
  553:  * This tree structure guarantees fast disk access and is the
  554:  * canonical way to implement M globals.
  555:  * 
  556:  * Each M global occupies a separate UNIX file in the directory
  557:  * specified in the globals_path directive for the current namespace 
  558:  * in /etc/freem.conf. The default namespace on a new installation
  559:  * of FreeM is called "USER".
  560:  *
  561:  * Any global whose name begins with "%" will always be stored in the
  562:  * SYSTEM namespace, in the directory specified in its "globals_path"
  563:  * directive in /etc/freem.conf (by default, /var/local/freem/SYSTEM/globals).
  564:  *
  565:  * The UNIX file names are the same as the corresponding M global
  566:  * names; i.e. beginning with an '^'.  However it is possible to access
  567:  * globals in other directories if the path name is specified.
  568:  * E.g. "S ^/usr/mumps/test=1" does "S ^test=1" in the file /usr/mumps/^test.
  569:  * If FreeM is started with the -s/--standard switches, it is not possible
  570:  * to specify a directory. There is a syntactic ambiguity: the '/' character
  571:  * in the directory name is in conflict with the '/' divide operator. Use
  572:  * parentheses to make things clear:
  573:  * 
  574:  * ^/usr/mumps/test/2              ; '/2' is part of the name
  575:  * (^/usr/mumps/test)/2            ; ambiguity resolved
  576:  * ^test/2                         ; '/2' is a divide operation
  577:  * ^/usr/mumps/test("ok")/2        ; '/2' is a divide
  578:  * 
  579:  * To prevent jobs from messing the globals up, access is regulated
  580:  * with the 'locking' mechanism. (that is different from mumps LOCKs)
  581:  * 
  582:  * Data is organized in blocks of 1024 bytes (BLOCKLEN) with the following
  583:  * layout:
  584:  * byte    0 - 1013 'stuff'                                  0...DATALIM
  585:  * organization is:
  586:  * length of key (minus offset into previous key)
  587:  * offset into previous key
  588:  * key (without EOL character)
  589:  * length of data               or two bytes as pointer
  590:  * data(without EOL character)     in pointer blocks
  591:  * 
  592:  * byte 1014 - 1016 leftlink pointer                             LLPTR
  593:  * in root block: number of blocks              NRBLK
  594:  * byte 1017        <reserved>
  595:  * byte 1017        in root block: type of collating sequence    COLLA
  596:  * LSB=0: numeric(standard) LSB=1: alphabetic
  597:  * byte 1018 - 1020 rightlink pointer                            RLPTR
  598:  * in root block: number of free blocks list    FREE
  599:  * byte 1021        block type                                   BTYP
  600:  * (2=POINTER,6=BOTTOM LEVEL POINTER,8=DATA)
  601:  * byte 1022 - 1023 offset                                       OFFS
  602:  * (pointer to unused part of 'stuff')
  603:  * 
  604:  * the file is *not* closed on return. since access is regulated by the
  605:  * locking mechanism, that will not spell trouble.
  606:  */
  607:  
  608: void global_bltin (short action, char *key, char *data)
  609: {
  610: 
  611:     global_handle *g;
  612: 
  613:     unsigned long hdr_offset;
  614:     
  615:     /* these must be static variables */
  616:     static short filedes;		/* filedescr for global access */
  617:     static char filnam[256];		/* name of global/unix file */
  618: 
  619:     /* the following vars may be */
  620:     /* static or dynamic */
  621:     static unsigned long blknbr;	/* block number */
  622:     static unsigned long newblk;
  623:     static unsigned long other;
  624:     static long j1;
  625:     static long limit;
  626:     static short typ;			/* block type */
  627:     static long keyl;			/* length of compacted key */
  628:     static long datal;			/* length of data */
  629:     static long olddatal;
  630:     static long offset;
  631:     static long found;
  632:     static long addr;			/* address of key in 'block' */
  633:     static long needed;			/* new bytes needed to ins. stuff */
  634:     static long ret_to;			/* return code */
  635:     static long kill_again;
  636:     static char key1[256];
  637:     static char tmp1[256];		/* intermediate storage for op= */
  638:     static char block[BLOCKLEN];
  639:     static int getnflag;		/* flag 1=$ZO-variable 0=$Q-function */
  640:     static int tryfast;			/* try fast access if get_sym on    */
  641:                                 /* previous global */
  642: 
  643:     int iresult;
  644:     
  645:     struct stat dinf;			/* get modification date */
  646: 
  647:     long savj;
  648:     long savch;			/* saved j and ch for multiple pathes */
  649:     register long int i;
  650:     register long int j;
  651:     register long int k;
  652:     register long int ch;
  653:     long pathscan;			/* flag for repeated scan of pathlist setting an undef global */
  654: 
  655:     hdr_offset = sizeof (global_header);
  656:     
  657:     /* process optional limitations */
  658:     if (glvnflag.all && key[0] >= '%' && key[0] <= 'z') {
  659: 
  660:         if ((i = glvnflag.one[0])) {	/* number of significant chars */
  661: 
  662:             j = 0;
  663:             while ((k = key[j]) != DELIM && k != EOL) {
  664: 
  665:                 if (j >= i) {
  666:                     
  667:                     while ((k = key[++j]) != DELIM && k != EOL);
  668: 
  669:                     stcpy (&key[i], &key[j]);
  670:                     
  671:                     break;
  672:                 }
  673: 
  674:                 j++;
  675: 
  676:             }
  677:         }
  678: 
  679:         if (glvnflag.one[1]) {		/* upper/lower sensitivity */
  680:             
  681:             j = 0;
  682:             
  683:             while ((k = key[j]) != DELIM && k != EOL) {
  684:             
  685:                 if (k >= 'a' && k <= 'z') key[j] = k - 32;
  686:             
  687:                 j++;
  688:             
  689:             }
  690: 
  691:         }
  692: 
  693:         if ((i = glvnflag.one[2])) {
  694: 
  695:             if (stlen (key) > i) {
  696:                 merr_raise (M75);
  697:                 return;
  698:             }				/* key length limit */
  699: 
  700:         }
  701: 
  702:         if ((i = glvnflag.one[3])) {	/* subscript length limit */
  703:             
  704:             j = 0;
  705:             
  706:             while ((k = key[j++]) != DELIM && k != EOL);
  707:             
  708:             if (k == DELIM) {
  709:             
  710:                 k = 0;
  711:                 for (;;) {
  712:             
  713:                     k = key[j++];
  714:             
  715:                     if (k == DELIM || k == EOL) {
  716:             
  717:                         if (k > i) {
  718:                             merr_raise (M75);
  719:                             return;
  720:                         }
  721:             
  722:                         k = 0;
  723:                     }
  724: 
  725:                     if (k == EOL) break;
  726:             
  727:                     k++;
  728:                 }
  729:             }
  730:         }
  731:     }
  732: 
  733: 
  734:     if (action == getnext) {
  735:         getnflag = TRUE;
  736:         varnam[0] = EOL;
  737:         
  738:         if (zref[0] == EOL) {
  739:             merr_raise (M7);
  740:             data[0] = EOL;
  741:         
  742:             return;
  743:         }
  744: 
  745:         stcpy (key, zref);
  746: 
  747:         action = fra_query;
  748:         ordercnt = 1L;
  749:     } 
  750:     else {
  751:     
  752:         getnflag = FALSE;
  753: 
  754:         /* naked reference section */
  755: 
  756:         if (key[1] == DELIM) {		/* resolve naked reference */
  757: 
  758:             while (--nakoffs >= 0) {	/* naked reference pointer */
  759:                 if (zref[nakoffs] == DELIM) break;
  760:             }
  761: 
  762:             if ((i = ++nakoffs) == 0) {	/* illegal naked reference */
  763:                 data[0] = EOL1;
  764:                 merr_raise (NAKED);
  765:             
  766:                 return;
  767:             }
  768: 
  769:             j = 2;
  770:             while ((zref[i] = key[j++]) != EOL) {
  771:                 
  772:                 if ((++i) >= STRLEN) {
  773:                     zref[255] = EOL;
  774:                     merr_raise (M75);
  775:                     
  776:                     return;
  777:                 }
  778: 
  779:             }
  780:             nakoffs = stcpy (key, zref);
  781:         } 
  782:         else {
  783: 
  784:             /* only save off $REFERENCE if the global isn't part of SSVN backing storage */
  785:             if (key[1] != '$') {
  786:                 nakoffs = stcpy (zref, key);	/* save reference */
  787:             }
  788: 
  789:         }
  790:     }
  791: 
  792:     if (v22ptr) {
  793: 
  794:         procv22 (key);
  795:         
  796:         if (key[0] != '^') {
  797:             char    losav[256];
  798: 
  799:             stcpy (losav, l_o_val);
  800:             symtab (action, key, data);
  801:             stcpy (g_o_val, l_o_val);
  802:             stcpy (l_o_val, losav);
  803: 
  804:             return;
  805:         }
  806:     }
  807: 
  808:     g = gbl_handle (key);    
  809:     i = gbl_path (key, filnam);
  810:         
  811:     /* compact key to internal format: characters are shifted left */
  812:     /* delimiters become LSB of previous character                 */
  813:     /* test subscripts for being numeric or not                    */
  814:     /* numeric values are shifted into the code space              */
  815:     /* that is available because of illegal CTRL subscipts         */
  816:     
  817:     k = 0;
  818: 
  819:     if (key[i] == EOL) {		/* unsubscripted variable */
  820:         
  821:         if (action == fra_order) {
  822:             g_o_val[0] = EOL;
  823:             merr_raise (NEXTER);
  824: 
  825:             return;
  826:         }
  827: 
  828:     } 
  829:     else if (key[++i] == EOL) {	/* empty (first) subscript */
  830:         
  831:         if ((action != fra_order) && (action != fra_query)) {
  832:             merr_raise (SBSCR);
  833:             return;
  834:         }
  835: 
  836:     } 
  837:     else {				/* non empty subscript */
  838:     
  839:         j1 = g_numeric (&key[i]);
  840:         
  841:         while ((ch = key[i++]) != EOL) {
  842: 
  843:             if (ch == DELIM) {
  844: 
  845:                 if (k == 0) {
  846:                     merr_raise (SBSCR);
  847:                     return;
  848:                 }
  849: 
  850:                 if (compactkey[--k] & 01) {
  851:                     merr_raise (SBSCR);
  852:                     return;
  853:                 }
  854: 
  855:                 compactkey[k++] |= 01;
  856:                 j1 = g_numeric (&key[i]);
  857: 
  858:             } 
  859:             else if (UNSIGN (ch) >= DEL) {	/* transform 8bit char to 7bit */
  860: 
  861:                 compactkey[k++] = (DEL << 1);
  862:                 ch = UNSIGN (ch) - DEL;
  863:                 
  864:                 if (UNSIGN (ch) >= DEL) {
  865:                     compactkey[k++] = (DEL << 1);
  866:                     ch = UNSIGN (ch) - DEL;
  867:                 }
  868:                 
  869:                 compactkey[k++] = ch << 1;
  870: 
  871:             } 
  872:             else if (ch < SP || ch >= DEL) {
  873:                 
  874:                 /*no CTRLs */
  875: 
  876:                 merr_raise (SBSCR);                
  877:                 return;
  878:             }
  879:             else { 
  880:                 compactkey[k++] = (j1 ? (ch << 1) & 036 : ch << 1);
  881:             }
  882:         }
  883: 
  884:     }
  885: 
  886:     if (action == fra_order) {
  887: 
  888:         if (ordercnt > 0) {
  889:             
  890:             compactkey[k] = (k == 0 || (compactkey[k - 1] & 01) ? ALPHA : OMEGA);
  891:         
  892:             if (k > 0) compactkey[k - 1] |= 01;
  893:             
  894:             keyl = (++k);
  895: 
  896:         } 
  897:         else if (ordercnt == 0) {	/* no scan at all */
  898:             
  899:             k = 0;
  900:             i = 0;
  901:             
  902:             while ((ch = key[i++]) != EOL) {
  903:                 if (ch == DELIM) k = i;                
  904:             }
  905:             
  906:             stcpy (data, &key[k]);
  907:             g_o_val[0] = EOL;
  908:             
  909:             return;
  910: 
  911:         } 
  912:         else {			/* backward scanning */
  913: 
  914:             if (k == 0 || (compactkey[k - 1] & 01)) {
  915:                 
  916:                 compactkey[k] = OMEGA;
  917: 
  918:                 if (k > 0) compactkey[k - 1] |= 01;
  919: 
  920:                 k++;
  921: 
  922:             } 
  923:             else {
  924:                 compactkey[k - 1] |= 01;
  925:             }
  926:             
  927:             keyl = k;
  928:         }
  929: 
  930:     } 
  931:     else {
  932:     
  933:         if ((keyl = k) > 0) {
  934:     
  935:             if ((compactkey[--k] & 01) && (action != fra_query)) {
  936:                 merr_raise (SBSCR);
  937:                 return;
  938:             }
  939:     
  940:             compactkey[k++] |= 01;
  941:         }
  942:     }
  943: 
  944:     compactkey[k] = g_EOL;
  945: 
  946: reopen:
  947: 
  948:     gbl_open (g, action);
  949:     if (g->fd == -1) {
  950: 
  951:         /* file not found */
  952:         if (action != set_sym) {
  953:             
  954:             if (errno != ENOENT) {
  955:                 merr_raise (PROTECT);
  956:                 return;
  957:             }
  958: 
  959:             if (action == fra_dat || action == zdata) {
  960:                 data[0] = '0';
  961:                 data[1] = EOL1;
  962:         
  963:                 return;
  964:             }
  965:         
  966:             data[0] = EOL1;
  967:         
  968:             if (action == get_sym || getnflag) {
  969:                 merr_raise (M7);
  970:                 data[0] = EOL;
  971:             } 
  972:             else if (action == fra_order || action == fra_query) {
  973:                 g_o_val[0] = EOL;
  974:             }
  975:         
  976:             return;
  977:         }
  978: 
  979:         if (errno != ENOENT) {
  980:             merr_raise (PROTECT);
  981:             return;
  982:         }
  983:         
  984:         if (setop) {
  985:             
  986:             tmp1[0] = EOL;
  987:             m_op (tmp1, data, setop);
  988:             setop = 0;
  989:             
  990:             if (merr () > OK) return;
  991: 
  992:             datal = stcpy (data, tmp1);
  993:         }
  994: 
  995:         for (i = 0; i < BLOCKLEN; block[i++] = 0);	/* clear block */
  996:         
  997:         stcpy0 (&block[2], compactkey, (long) keyl);
  998:         
  999:         block[0] = keyl;		/* $length of key */
 1000:         j = i = keyl + 2;
 1001:         block[i++] = 0;
 1002:         block[i++] = 0;
 1003:         block[i++] = ROOT + 1;		/* block 1 = data */
 1004:         block[BTYP] = BOTTOM;
 1005:         block[COLLA] = 0;		/* collating sequence */
 1006:         block[OFFS] = i / 256;
 1007:         block[OFFS + 1] = i % 256;
 1008:         block[NRBLK] = 0;
 1009:         block[NRBLK + 1] = 0;
 1010:         block[NRBLK + 2] = ROOT + 1;	/* nr. of blocks */
 1011: 
 1012:         /* create file, write_lock it and initialize root block */
 1013:         gbl_lock (g, 1);
 1014: 
 1015:         if ((iresult = gbl_create (g)) != OK) {
 1016:             merr_raise (iresult);
 1017:             return;
 1018:         }        
 1019:         
 1020:         for (;;) {
 1021:             
 1022:             errno = 0;
 1023:         
 1024:             lseek (g->fd, hdr_offset + (ROOT * BLOCKLEN), SEEK_SET);
 1025:             write (g->fd, block, BLOCKLEN);
 1026:         
 1027:             if (errno == 0) break;
 1028:         
 1029:             panic ();
 1030:         }
 1031: 
 1032:         block[NRBLK] = 0;
 1033:         block[NRBLK + 1] = 0;
 1034:         block[NRBLK + 2] = ROOT;	/* clear */
 1035: 
 1036:         /* copy and write length of data */
 1037:         block[j] = k = stcpy (&block[j + 1], data);
 1038:         block[i = k + j + 1] = 0;	/* clear EOL symbol */
 1039:         block[BTYP] = DATA;		/* type */
 1040:         block[OFFS] = i / 256;
 1041:         block[OFFS + 1] = i % 256;
 1042:         
 1043:         for (;;) {
 1044: 
 1045:             errno = 0;
 1046:             write (g->fd, block, BLOCKLEN);
 1047:             
 1048:             if (errno == 0) break;
 1049:             
 1050:             lseek (g->fd, hdr_offset + ((ROOT + 1L) * BLOCKLEN), SEEK_SET);
 1051:             panic ();
 1052: 
 1053:         }
 1054: 
 1055:         gbl_close (g);
 1056:         gbl_unlock (g);
 1057:         gbl_open (g, action);
 1058: 
 1059:         /* close new file, so other users can find it */
 1060:         return;
 1061:     }
 1062: 
 1063:     /* request global for exclusive use                            */
 1064:     /* odd numbered actions get read access (get_sym,data,fra_order) 3 */
 1065:     /* even ones read/write access          (set_sym,kill_sym)   1 */
 1066: 
 1067: lock:
 1068: 
 1069:     if (action == get_sym) {
 1070: 
 1071: tfast0:
 1072:         gbl_lock (g, 3);
 1073:         
 1074:         if (g->fast_path > 0) goto tfast1;		/* try again last block */
 1075:         
 1076:         blknbr = g->last_block = ROOT;		/* start with ROOT block */
 1077:         
 1078:         for (;;) {
 1079: 
 1080: 
 1081: tfast1:
 1082: 
 1083:             lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1084:             read (g->fd, block, BLOCKLEN);
 1085: 
 1086: 
 1087: tfast2:
 1088: 
 1089:         if ((typ = block[BTYP]) == DATA) {	/* scan data block: here we test for equality only */
 1090: 
 1091:             offset = UNSIGN (block[OFFS]) * 256 +            
 1092:             UNSIGN (block[OFFS + 1]);
 1093:             j = UNSIGN (block[0]);
 1094:             i = 0;
 1095: 
 1096:             stcpy0 (key1, &block[2], j);	/* get first key */
 1097:             
 1098:             ch = keyl;		/* ch is a register! */
 1099:             
 1100:             while (i < offset) {
 1101:             
 1102:                 j = UNSIGN (block[i++]);	/* length of key - offset */
 1103:                 k = UNSIGN (block[i++]);	/* offset into previous entry */
 1104: 
 1105:                 j += k;
 1106:             
 1107:                 while (k < j) key1[k++] = block[i++];		/* get key */
 1108: 
 1109:                 if (j != ch) {	/* keys have different length */
 1110:                     
 1111:                     i += UNSIGN (block[i]);
 1112:                     i++;
 1113: 
 1114:                     continue;
 1115: 
 1116:                 }
 1117: 
 1118:                 j = ch;
 1119:                 
 1120:                 do {
 1121:                     j--;
 1122:                 } while (compactkey[j] == key1[j]);		/* compare keys */
 1123:                 
 1124: 
 1125:                 if (j < 0) {
 1126:                     
 1127:                     k = UNSIGN (block[i++]);
 1128:                     stcpy0 (data, &block[i], k);	/* get value */
 1129:                     data[k] = EOL1;	/* append EOL */
 1130: 
 1131:                     goto quit;
 1132: 
 1133:                 }
 1134: 
 1135:                 i += UNSIGN (block[i]);
 1136:                 i++;		/* skip data */
 1137: 
 1138:             }
 1139: 
 1140:             /* fast access failed. try normal path */
 1141:             if (tryfast) {
 1142:                 gbl_cache_miss (g);
 1143:                 goto tfast0;
 1144:             }
 1145: 
 1146:             merr_raise (M7);
 1147:             data[0] = EOL;
 1148:             
 1149:             goto quit;		/* variable not found */
 1150:         } 
 1151:         else {
 1152:         
 1153:             if (g->fast_path > 0) {
 1154:                 gbl_cache_miss (g);
 1155:                 goto tfast0;
 1156:             }
 1157: 
 1158:             if (typ == EMPTY) {
 1159:                 
 1160:                 if (blknbr == ROOT) {
 1161:                     //close (filedes);
 1162:                     gbl_close (g);
 1163:                     goto reopen;
 1164:                 }
 1165: 
 1166:                 merr_raise (DBDGD);
 1167:                 goto quit;
 1168: 
 1169:             }
 1170: 
 1171:         }
 1172: 
 1173:         scanpblk (block, &addr, &found);
 1174: 
 1175:         addr += UNSIGN (block[addr]) + 2;	/* skip key */
 1176:         
 1177:         if ((blknbr = UNSIGN (block[addr]) * 65536 + UNSIGN (block[addr + 1]) * 256 + UNSIGN (block[addr + 2])) == g->last_block) {
 1178:             merr_raise (DBDGD);
 1179:             goto quit;
 1180:         }
 1181: 
 1182:         addr += PLEN;		/* skip data */
 1183:         g->last_block = blknbr;
 1184:         g->fast_path = 1;
 1185:         
 1186:         if (merr () == INRPT) goto quit;
 1187: 
 1188:         }
 1189:     }					/* end of get_sym */
 1190: 
 1191:     gbl_lock (g, action & 01 ? 3 : 1);
 1192:     
 1193:     /* a KILL on an unsubscripted global deletes the entire file */
 1194:     if (action == kill_sym && compactkey[0] == g_EOL) {
 1195:         
 1196:         lseek (g->fd, hdr_offset + ROOT, SEEK_SET);
 1197: 
 1198:         /* note : UNIX does not tell other    */
 1199:         block[BTYP] = EMPTY;		/* jobs that a file has been unlinked */
 1200:         
 1201:         /* as long as they keep it open.      */
 1202:         /* so we mark this global as EMPTY    */
 1203:         write (g->fd, block, BLOCKLEN);
 1204: 
 1205:         gbl_unlock (g);
 1206:         gbl_close (g);
 1207:         
 1208:         unlink (filnam);
 1209:         
 1210:         return;
 1211:     }
 1212: 
 1213: k_again:				/* entry point for repeated kill operations */
 1214: 
 1215:     /* scan tree for the proper position of key */
 1216:     blknbr = g->last_block = ROOT;		/* start with ROOT block */
 1217:     trx = (-1);
 1218: 
 1219:     for (;;) {
 1220:         
 1221:         if (++trx >= TRLIM) {
 1222:             merr_raise (STKOV);
 1223:             goto quit;
 1224:         }
 1225: 
 1226:         traceblk[trx] = blknbr;
 1227:         traceadr[trx] = 0;
 1228:         
 1229:         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1230:         read (g->fd, block, BLOCKLEN);
 1231:         
 1232:         typ = block[BTYP];
 1233:         
 1234:         if (typ == DATA) {
 1235:             scandblk (block, &addr, &found);
 1236:             break;
 1237:         }
 1238: 
 1239:         if (typ == EMPTY) {
 1240: 
 1241:             if (blknbr == ROOT) {
 1242:                 gbl_close (g);
 1243:                 goto reopen;
 1244:             }
 1245: 
 1246:             merr_raise (DBDGD);
 1247:             goto quit;
 1248:         }
 1249: 
 1250:         scanpblk (block, &addr, &found);
 1251:         
 1252:         traceadr[trx] = addr;
 1253:         addr += UNSIGN (block[addr]);
 1254:         addr += 2;			/* skip key */
 1255:         
 1256:         if ((blknbr = UNSIGN (block[addr]) * 65536 + UNSIGN (block[addr + 1]) * 256 + UNSIGN (block[addr + 2])) == g->last_block) {
 1257:             merr_raise (DBDGD);
 1258:             goto quit;
 1259:         }
 1260: 
 1261:         addr += PLEN;			/* skip data */
 1262:         g->last_block = blknbr;
 1263:         g->fast_path = 1;
 1264:     }
 1265: 
 1266:     traceadr[trx] = addr;
 1267: 
 1268:     switch (action) {
 1269: 
 1270:         case set_sym:
 1271: 
 1272:             datal = stlen (data);
 1273:             offset = UNSIGN (block[OFFS]) * 256 +
 1274:             UNSIGN (block[OFFS + 1]);
 1275: 
 1276:             if (found != 2) {		/* new entry */
 1277:                 
 1278:                 if (setop) {
 1279: 
 1280:                     tmp1[0] = EOL;
 1281:                     
 1282:                     m_op (tmp1, data, setop);
 1283:                     
 1284:                     setop = 0;
 1285:                     
 1286:                     if (merr () > OK) return;
 1287:                     
 1288:                     datal = stcpy (data, tmp1);
 1289:                 
 1290:                 }
 1291: 
 1292:                 needed = keyl + datal + 3;
 1293:                 
 1294:                 if ((offset + needed) > DATALIM) {
 1295:                     ret_to = 'n';		/* n=new */
 1296:                     goto splitd;
 1297:                 }
 1298: 
 1299: 
 1300: s10:            {
 1301:                     long    len;		/*  insert key */
 1302:                     char    key0[256];
 1303: 
 1304:                     i = 0;
 1305: 
 1306:                     while (i < addr) {	/* compute offset into previous entry */
 1307:                         
 1308:                         len = UNSIGN (block[i++]);
 1309:                         
 1310: #ifdef VERSNEW
 1311: 
 1312:                         k = UNSIGN (block[i++]);
 1313:                         stcpy0 (&key0[k], &block[i], len);
 1314: 
 1315:                         i += len;
 1316:                         key0[k + len] = g_EOL;
 1317: 
 1318: #else
 1319: 
 1320:                         len += (k = UNSIGN (block[i++]));
 1321:                         
 1322:                         while (k < len) key0[k++] = block[i++];
 1323:                         
 1324:                         key0[k] = g_EOL;
 1325: 
 1326: #endif /* VERSNEW */
 1327: 
 1328:                         i += UNSIGN (block[i]);
 1329:                         i++;		/* skip data */
 1330: 
 1331:                     }
 1332: 
 1333:                     k = 0;
 1334:                     
 1335:                     if (addr > 0) {
 1336: 
 1337:                         while (compactkey[k] == key0[k]) {                            
 1338:                             
 1339:                             if (key[k] == g_EOL) break;
 1340:                             
 1341:                             k++;
 1342: 
 1343:                         }
 1344: 
 1345:                         /* do *not* fully compact numerics */
 1346:                         if ((i = UNSIGN (compactkey[k])) <= POINT) {
 1347:                         
 1348:                             while (--k >= 0 && (UNSIGN (compactkey[k]) & 01) == 0);
 1349:                         
 1350:                             k++;
 1351:                         }
 1352: 
 1353:                     }
 1354: 
 1355:                     needed -= k;
 1356:                     i = (offset += needed);
 1357:                     block[OFFS] = i / 256;
 1358:                     block[OFFS + 1] = i % 256;
 1359: 
 1360:                     while (i >= addr) {
 1361:                         block[i] = block[i - needed];
 1362:                         i--;
 1363:                     }
 1364: 
 1365: #ifdef VERSNEW
 1366: 
 1367:                     i = addr;
 1368:                     block[i++] = j1 = keyl - k;
 1369:                     block[i++] = k;
 1370: 
 1371:                     stcpy0 (&block[i], &compactkey[k], j1);
 1372:                     
 1373:                     i += j1;
 1374:                     block[i++] = datal;
 1375:                     
 1376:                     stcpy0 (&block[i], data, datal);
 1377: 
 1378: #else
 1379:                     
 1380:                     block[addr + 1] = k;
 1381:                     j1 = k;
 1382:                     i = addr + 2;
 1383:                     
 1384:                     while (k < keyl) block[i++] = compactkey[k++];
 1385: 
 1386:                     block[addr] = k - j1;
 1387:                     addr = i++;
 1388:                     k = 0;
 1389:                     
 1390:                     while (k < datal) block[i++] = data[k++];
 1391: 
 1392:                     block[addr] = k;
 1393: 
 1394: #endif /* VERSNEW */
 1395: 
 1396:                 }
 1397: 
 1398:                 lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1399:                 write (g->fd, block, BLOCKLEN);
 1400: 
 1401:                 if (traceadr[trx] == 0) update (g, compactkey, keyl);
 1402: 
 1403:                 break;
 1404:             }
 1405: 
 1406:             /* there was a previous entry */
 1407:             addr += UNSIGN (block[addr]);
 1408:             addr += 2;
 1409:             olddatal = UNSIGN (block[addr]);
 1410:             
 1411:             if (setop) {
 1412: 
 1413:                 stcpy0 (tmp1, &block[addr + 1], (long) olddatal);
 1414:                 
 1415:                 tmp1[olddatal] = EOL;
 1416:                 
 1417:                 m_op (tmp1, data, setop);
 1418:                 
 1419:                 setop = 0;
 1420:                 
 1421:                 if (merr () > OK) return;
 1422: 
 1423:                 datal = stcpy (data, tmp1);
 1424:             }
 1425: 
 1426:             if ((j1 = olddatal - datal) != 0) {
 1427: 
 1428:                 if (j1 > 0) {		/* surplus space */
 1429: 
 1430:                     i = addr + datal;
 1431:                     k = offset;
 1432:                     offset -= j1;
 1433:                     j1 += i;
 1434: 
 1435:                     stcpy0 (&block[i], &block[j1], offset - i);
 1436:                     
 1437:                     i = offset;
 1438:                     
 1439:                     while (i < k) block[i++] = 0;	/* clear area */
 1440: 
 1441:                 } 
 1442:                 else {			
 1443:                     /* we need more space */ 
 1444: 
 1445:                     if ((offset - j1) > DATALIM) {
 1446:                         /* block too small */
 1447:                         ret_to = 'u';	/* u=update */
 1448: 
 1449:                         goto splitd;
 1450:                     }
 1451: 
 1452: s20:
 1453:                     
 1454:                     i = offset;
 1455:                     k = addr + olddatal;
 1456:                     offset -= j1;
 1457:                     j1 = offset;
 1458:                     
 1459:                     while (i > k) block[j1--] = block[i--];
 1460: 
 1461:                 }
 1462: 
 1463:                 /* overwrite */
 1464:                 block[OFFS] = offset / 256;
 1465:                 block[OFFS + 1] = offset % 256;
 1466:                 block[addr] = datal;
 1467: 
 1468:             } 
 1469:             else {			/* if nothing changes, do not write */
 1470: 
 1471:                 i = 0;
 1472:                 j = addr + 1;
 1473:                 
 1474:                 while (i < datal) {
 1475:                     if (block[j++] != data[i]) break;
 1476:                     
 1477:                     i++;
 1478:                 }
 1479: 
 1480:                 if (i == datal) goto quit;
 1481:             
 1482:             }
 1483:     
 1484:             stcpy0 (&block[++addr], data, (long) datal);
 1485:             lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1486:             write (g->fd, block, BLOCKLEN);
 1487: 
 1488:             gbl_update_tid (g);
 1489:             
 1490:             break;
 1491: 
 1492: 
 1493:         case fra_dat:
 1494: 
 1495:             data[0] = '0';
 1496:             data[1] = EOL1;
 1497:             data[2] = EOL1;
 1498:             
 1499:             if (found == 2) {		/* ... advance to next entry */
 1500:                 addr += UNSIGN (block[addr]);
 1501:                 addr += 2;			/* skip key */
 1502:                 addr += UNSIGN (block[addr]);
 1503:                 addr++;			/* skip data */
 1504: 
 1505:                 data[0] = '1';
 1506:             } 
 1507: 
 1508:             {
 1509:                 long    len;
 1510:                 char    key0[256];
 1511: 
 1512:                 /* get following entry, eventually in the next blk */
 1513:                 offset = UNSIGN (block[OFFS]) * 256 +
 1514:                 UNSIGN (block[OFFS + 1]);
 1515: 
 1516:                 if (addr >= offset) {
 1517: 
 1518:                     if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]))) {
 1519:                     
 1520:                         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1521:                         read (g->fd, block, BLOCKLEN);
 1522:                         j1 = UNSIGN (block[0]);
 1523:                     
 1524:                         i = 0;
 1525:                         j = 2;
 1526:                     
 1527:                         while (i < j1) key0[i++] = block[j++];
 1528:                     
 1529:                         key0[i] = g_EOL;
 1530:                     
 1531:                     } 
 1532:                     else {
 1533:                         goto quit;
 1534:                     }
 1535: 
 1536:                 } 
 1537:                 else {
 1538: 
 1539:                     i = 0;
 1540:                     
 1541:                     while (i <= addr) {	/* compute offset complete key */
 1542:                         len = UNSIGN (block[i++]);
 1543: 
 1544: #ifdef VERSNEW
 1545: 
 1546:                         k = UNSIGN (block[i++]);
 1547:                         stcpy0 (&key0[k], &block[i], len);
 1548:                         key0[k + len] = g_EOL;
 1549:                         i += len;
 1550: 
 1551: #else
 1552: 
 1553:                         len += (j = UNSIGN (block[i++]));
 1554:                         
 1555:                         while (j < len) key0[j++] = block[i++];
 1556:                         
 1557:                         key0[j] = g_EOL;
 1558: 
 1559: #endif /* VERSNEW */
 1560: 
 1561:                         i += UNSIGN (block[i]);
 1562:                         i++;		/* skip data */
 1563:                     }
 1564: 
 1565:                 }
 1566: 
 1567:                 /* is it a descendant? */
 1568:                 if (compactkey[0] == g_EOL && key0[0] != g_EOL) {
 1569:                     data[1] = data[0];
 1570:                     data[0] = '1';
 1571: 
 1572:                     break;
 1573:                 }
 1574: 
 1575:                 i = 0;
 1576:                 
 1577:                 while (compactkey[i] == key0[i]) i++;
 1578:                 
 1579:                 if (compactkey[i] == g_EOL) {
 1580:                     data[1] = data[0];
 1581:                     data[0] = '1';
 1582:                 }
 1583:             }
 1584: 
 1585:             break;
 1586: 
 1587: 
 1588:         case fra_order:
 1589: 
 1590:             if (ordercnt < 0) goto zinv;
 1591: 
 1592:             offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
 1593:             
 1594:             if (addr >= offset) {		/* look in next block */
 1595:             
 1596:                 if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
 1597:                     data[0] = EOL1;
 1598:                     g_o_val[0] = EOL;
 1599:                 
 1600:                     goto quit;
 1601:                 }	/* no next block */
 1602:                 
 1603:                 lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1604:                 read (g->fd, block, BLOCKLEN);
 1605:                 scandblk (block, &addr, &found);
 1606: 
 1607:             } 
 1608: 
 1609:             {
 1610:                 long    len;
 1611:                 int     ch0;
 1612:                 char    scratch[256];
 1613:                 char    key0[256];
 1614: 
 1615:                 i = 0;
 1616: 
 1617:                 while (i <= addr) {		/* compute offset complete key */
 1618:                     
 1619:                     len = UNSIGN (block[i++]);
 1620:                     len += (j = UNSIGN (block[i++]));
 1621:                     
 1622:                     while (j < len) key0[j++] = block[i++];
 1623:                     
 1624:                     key0[j] = g_EOL;
 1625:                     i += UNSIGN (block[i]);
 1626: 
 1627:                     i++;			/* skip data */
 1628:                 }
 1629: 
 1630:                 /* save data value for inspection with $V(111) */
 1631:                 i = addr;
 1632:                 i += UNSIGN (block[i]);
 1633:                 i += 2;			/* skip key */
 1634:                 j = UNSIGN (block[i++]);
 1635:                 stcpy0 (g_o_val, &block[i], j);	/* get value */
 1636:                 g_o_val[j] = EOL;		/* append EOL */
 1637: 
 1638:                 i = 0;
 1639:                 j = 0;
 1640:                 
 1641:                 while ((scratch[j++] = UNSIGN (key0[i++])) != g_EOL);
 1642:                 
 1643:                 if (compactkey[--keyl] == ALPHA) keyl++;
 1644:                 
 1645:                 /* count subscripts of key */
 1646:                 i = 0;
 1647:                 j1 = 0;
 1648:                 
 1649:                 while (i < keyl) if (compactkey[i++] & 01)
 1650:                 
 1651:                 j1++;
 1652:                 i = 0;
 1653:                 j = 0;
 1654:                 k = 0;
 1655:                 
 1656:                 while (i < keyl) {
 1657: 
 1658:                     if (scratch[i] != compactkey[j++]) {
 1659:                         k++;
 1660:                         break;
 1661:                     }
 1662: 
 1663:                     if (scratch[i++] & 01) k++;
 1664: 
 1665:                 }
 1666: 
 1667:                 if (k < j1) {
 1668:                     data[0] = EOL1;
 1669:                     g_o_val[0] = EOL;
 1670: 
 1671:                     goto quit;
 1672:                 }
 1673: 
 1674:                 while (--i >= 0) {
 1675:                     if ((scratch[i] & 01)) break;
 1676:                 }
 1677: 
 1678:                 i++;
 1679:                 j = 0;
 1680: 
 1681:                 while ((ch = UNSIGN (scratch[i++])) != g_EOL) {
 1682: 
 1683:                     ch0 = (ch >= SP ? (ch >> 1) :	/* 'string' chars */
 1684:                     (ch < 20 ? (ch >> 1) + '0' :	/* 0...9          */
 1685:                     (ch >> 1) + SP));	/* '.' or '-'     */
 1686: 
 1687: 
 1688:                     if (ch0 == DEL) {
 1689:                         
 1690:                         if (((ch = UNSIGN (scratch[i++])) >> 1) == DEL) {
 1691:                             ch0 += DEL;
 1692:                             ch = UNSIGN (scratch[i++]);
 1693:                         }
 1694:                     
 1695:                         ch0 += (ch >> 1);
 1696:                     }
 1697: 
 1698:                     data[j++] = ch0;
 1699:                     
 1700:                     if (ch & 01) break;
 1701: 
 1702:                 }
 1703: 
 1704:                 /* forget that data value if $d=10 */
 1705:                 if (UNSIGN (scratch[i]) != g_EOL) g_o_val[0] = EOL;
 1706: 
 1707:                 data[j] = EOL1;
 1708:                 ordercounter++;
 1709:                 
 1710:                 if (--ordercnt > 0) {	/* repeated forward scanning */
 1711:                     
 1712:                     if (ch != g_EOL) scratch[i] = g_EOL;
 1713:                     
 1714:                     stcpy0 (compactkey, scratch, i + 1);
 1715:                     
 1716:                     compactkey[i - 1] |= 01;
 1717:                     compactkey[i] = OMEGA;
 1718:                     keyl = i + 1;
 1719:                     
 1720:                     goto k_again;
 1721: 
 1722:                 }
 1723: 
 1724:             }
 1725: 
 1726:             break;
 1727: 
 1728: 
 1729:         case fra_query:
 1730: 
 1731:             if (ordercnt < 1) {
 1732:                 merr_raise (ARGLIST);
 1733:                 goto quit;
 1734:             }
 1735: 
 1736:             if (found == 2) {		/* ... advance to next entry */
 1737:                 addr += UNSIGN (block[addr]);
 1738:                 addr += 2;			/* skip key */
 1739:                 addr += UNSIGN (block[addr]);
 1740:                 addr++;			/* skip data */
 1741:             }
 1742: 
 1743:             offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
 1744: 
 1745:             while (--ordercnt > 0) {	/* repeated forward query */
 1746: 
 1747:                 addr += UNSIGN (block[addr]);
 1748:                 addr += 2;			/* skip key */
 1749:                 addr += UNSIGN (block[addr]);
 1750:                 addr++;			/* skip data */
 1751:                 
 1752:                 if (addr >= offset) {	/* look in next block */
 1753:                     
 1754:                     if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
 1755:                         data[0] = EOL1;
 1756:                         
 1757:                         goto quit;		/* no next block */
 1758:                     }
 1759: 
 1760:                     lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1761:                     read (g->fd, block, BLOCKLEN);
 1762: 
 1763:                     addr = 0;
 1764:                     offset = UNSIGN (block[OFFS]) * 256 +
 1765:                     UNSIGN (block[OFFS + 1]);
 1766:                 }
 1767: 
 1768:             }
 1769: 
 1770:             if (addr >= offset) {		/* look in next block */
 1771: 
 1772:                 if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
 1773:                 
 1774:                     if (getnflag) {
 1775:                         zref[0] = EOL;
 1776:                         merr_raise (ARGER);
 1777:                     }
 1778: 
 1779:                     data[0] = EOL1;
 1780:                 
 1781:                     goto quit;		/* no next block */
 1782:                 }
 1783: 
 1784:                 lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 1785:                 read (g->fd, block, BLOCKLEN);
 1786:                 
 1787:                 addr = 0;
 1788:             } 
 1789: 
 1790:             {
 1791:                 long    len;
 1792:                 char    key0[256];
 1793: 
 1794:                 i = 0;
 1795: 
 1796:                 while (i <= addr) {		/* compute offset complete key */
 1797: 
 1798:                     len = UNSIGN (block[i++]);
 1799:                     len += (j = UNSIGN (block[i++]));
 1800:                 
 1801:                     while (j < len) key0[j++] = block[i++];
 1802: 
 1803:                     key0[j] = g_EOL;
 1804:                     k = i;			/* save i for getnflag processing */
 1805:                     i += UNSIGN (block[i]);
 1806:                     i++;			/* skip data */
 1807: 
 1808:                 }
 1809: 
 1810:                 if (getnflag) {
 1811: 
 1812:                     int ch0;
 1813: 
 1814:                     i = k;
 1815:                     k = UNSIGN (block[i++]);
 1816: 
 1817:                     stcpy0 (data, &block[i], k);	/* get value */
 1818:                     
 1819:                     data[k] = EOL1;		/* append EOL */
 1820:                     j = 0;
 1821:                     
 1822:                     while (zref[j] != DELIM && zref[j] != EOL) j++;
 1823:                     
 1824:                     if (zref[j] == EOL) zref[j] = DELIM;
 1825: 
 1826:                     nakoffs = j;
 1827:                     j++;
 1828:                     i = 0;			/* make this ref $ZR */
 1829:                     
 1830:                     while ((ch = UNSIGN (key0[i++])) != g_EOL) {
 1831: 
 1832:                         ch0 = (ch >= SP ? (ch >> 1) :	/* 'string' chars */
 1833:                         (ch < 20 ? (ch >> 1) + '0' :		/* 0...9          */
 1834:                         (ch >> 1) + SP));	/* '.' or '-'     */
 1835: 
 1836: 
 1837:                         if (ch0 == DEL) {
 1838: 
 1839:                             if (((ch = UNSIGN (key0[i++])) >> 1) == DEL) {
 1840:                                 ch0 += DEL;
 1841:                                 ch = UNSIGN (key0[i++]);
 1842:                             }
 1843: 
 1844:                             ch0 += (ch >> 1);
 1845: 
 1846:                         }
 1847: 
 1848:                         zref[j++] = ch0;
 1849: 
 1850:                         
 1851:                         if (j >= 252) {
 1852:                             zref[j] = EOL;
 1853:                             merr_raise (M75);
 1854:                             
 1855:                             goto quit;
 1856:                         }
 1857: 
 1858:                         if (ch & 01) {
 1859:                             nakoffs = j;
 1860:                             zref[j++] = DELIM;
 1861:                         }
 1862: 
 1863:                     }
 1864: 
 1865:                     zref[--j] = EOL;
 1866:                     
 1867:                     break;
 1868: 
 1869:                 } 
 1870:                 else {			/* save data value for inspection with $V(111) */
 1871:                 
 1872:                     int ch0;
 1873: 
 1874:                     i = addr;
 1875:                     i += UNSIGN (block[i]);
 1876:                     i += 2;			/* skip key */
 1877:                     j = UNSIGN (block[i++]);
 1878: 
 1879:                     stcpy0 (g_o_val, &block[i], j);		/* get value */
 1880:                     
 1881:                     g_o_val[j] = EOL;	/* append EOL */
 1882: 
 1883:                     j = 0;
 1884:                     i = 0;
 1885:                     
 1886:                     while ((data[j] = zref[j]) != DELIM) {
 1887: 
 1888:                         if (data[j] == EOL1) {
 1889:                             data[j] = '(';
 1890:                             break;
 1891:                         }
 1892:             
 1893:                         j++;
 1894:             
 1895:                     }
 1896:             
 1897:                     data[j++] = '(';
 1898:                     k = 1;
 1899: 
 1900:                     while ((ch = UNSIGN (key0[i++])) != g_EOL) {
 1901:                         int     typ;
 1902: 
 1903:                         if (k) {
 1904:                             k = 0;
 1905: 
 1906:                             if ((typ = (ch > SP))) data[j++] = '"';
 1907:                         }
 1908: 
 1909:                         ch0 = (ch >= SP ? (ch >> 1) :	/* 'string' chars */
 1910:                         (ch < 20 ? (ch >> 1) + '0' :		/* 0...9          */
 1911:                         (ch >> 1) + SP));	/* '.' or '-'     */
 1912:                         
 1913:                         if (ch0 == DEL) {
 1914: 
 1915:                             if (((ch = UNSIGN (key0[i++])) >> 1) == DEL) {
 1916:                                 ch0 += DEL;
 1917:                                 ch = UNSIGN (key0[i++]);
 1918:                             }
 1919:                             
 1920:                             ch0 += (ch >> 1);
 1921:                         }
 1922: 
 1923:                         data[j] = ch0;
 1924:                         
 1925:                         if (j >= 252) {
 1926:                             data[j] = EOL1;
 1927:                             merr_raise (M75);
 1928:                             
 1929:                             goto quit;
 1930:                         }
 1931: 
 1932:                         if (data[j++] == '"') data[j++] = '"';
 1933: 
 1934:                         if (ch & 01) {
 1935:                             
 1936:                             if (typ) data[j++] = '"';
 1937:                         
 1938:                             data[j++] = ',';
 1939:                             k = 1;
 1940: 
 1941:                         }
 1942:                     }
 1943: 
 1944:                     data[j--] = EOL1;
 1945:                     data[j] = ')';
 1946: 
 1947:                 }
 1948:             }
 1949: 
 1950:             break;
 1951: 
 1952: 
 1953:         case kill_sym:			/* search and destroy */
 1954:     
 1955: killo:				/* entry from killone section */
 1956:             offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
 1957: 
 1958:             i = 0;
 1959:             key1[0] = g_EOL;
 1960:             
 1961:             while (i < addr) {		/* compute complete key */
 1962:                 
 1963:                 k = UNSIGN (block[i++]);
 1964:                 k += (j = UNSIGN (block[i++]));
 1965:                 
 1966:                 while (j < k) key1[j++] = block[i++];
 1967: 
 1968:                 key1[j] = g_EOL;
 1969:                 i += UNSIGN (block[i]);
 1970: 
 1971:                 i++;			/* skip data */
 1972: 
 1973:             }
 1974: 
 1975:             /* look whether there's something to do at all */
 1976:             if (found != 2) {		/* is it a descendant ? */
 1977: 
 1978:                 char key0[256];
 1979:                 long trxsav;
 1980: 
 1981:                 if (addr >= offset) {	/* nothing to kill in that block */
 1982:                 
 1983:                     blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]);
 1984:                 
 1985:                     if (blknbr == 0) break;		/* there is no next block */
 1986: 
 1987:                     /* maybe there's something in the next block ... */
 1988:                     trxsav = trx;
 1989: 
 1990:                     for (;;) {
 1991: 
 1992:                         other = traceblk[--trx];
 1993:                         addr = traceadr[trx];
 1994:                         
 1995:                         lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 1996:                         read (g->fd, block, BLOCKLEN);
 1997:                         
 1998:                         addr += UNSIGN (block[addr]);
 1999:                         addr += (2 + PLEN);	/* skip previous entry */
 2000:                         offset = UNSIGN (block[OFFS]) * 256 +
 2001:                         UNSIGN (block[OFFS + 1]);
 2002:                         traceadr[trx] = addr;
 2003:                         
 2004:                         if (addr < offset) break;
 2005:                         
 2006:                         traceadr[trx] = 0;
 2007:                         traceblk[trx] = UNSIGN (block[RLPTR]) * 65536 +
 2008:                         UNSIGN (block[RLPTR + 1]) * 256 +
 2009:                         UNSIGN (block[RLPTR + 2]);
 2010: 
 2011:                     }
 2012: 
 2013:                     trx = trxsav;
 2014: 
 2015:                     lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2016:                     read (g->fd, block, BLOCKLEN);
 2017: 
 2018:                     offset = UNSIGN (block[OFFS]) * 256 +
 2019:                     UNSIGN (block[OFFS + 1]);
 2020:                     addr = 0;
 2021:                     k = UNSIGN (block[0]);
 2022:                     stcpy0 (key0, &block[2], k);
 2023:                     key0[k] = g_EOL;
 2024: 
 2025:                 } 
 2026:                 else {			/* get following entry */
 2027: 
 2028:                     stcpy0 (key0, key1, j);
 2029:                     i = addr;
 2030:                     k = UNSIGN (block[i++]);
 2031:                     k += (j = UNSIGN (block[i++]));
 2032:                 
 2033:                     while (j < k) key0[j++] = block[i++];
 2034:                 
 2035:                     key0[j] = g_EOL;
 2036:                 }
 2037: 
 2038:                 /* is it a descendant? */
 2039:                 i = 0;
 2040: 
 2041:                 while (compactkey[i] == key0[i]) i++;
 2042:                 
 2043:                 if (compactkey[i] != g_EOL) break;			/* nothing to kill */
 2044:             }
 2045: 
 2046:             /* scan this block for all descendants */
 2047:             {
 2048: 
 2049:                 long begadr, endadr, len;
 2050:                 char key0[256];
 2051: 
 2052:                 stcpy0 (key0, compactkey, (long) keyl);
 2053: 
 2054:                 begadr = endadr = i = addr;
 2055:                 
 2056:                 if (action == killone) {
 2057:                     
 2058:                     i += UNSIGN (block[i]);
 2059:                     i += 2;			/* skip key */
 2060:                     i += UNSIGN (block[i]);
 2061:                     i++;			/* skip data */
 2062: 
 2063:                     endadr = i;
 2064:                 } 
 2065:                 else {
 2066: 
 2067:                     while (i < offset) {
 2068: 
 2069:                         len = UNSIGN (block[i++]);
 2070:                         k = j = UNSIGN (block[i++]);
 2071:                         
 2072:                         if (k >= keyl) {
 2073:                             i += len;
 2074:                         }
 2075:                         else {
 2076: 
 2077:                             len += k;
 2078:                             
 2079:                             while (j < len) key0[j++] = block[i++];
 2080: 
 2081:                             key0[j] = g_EOL;
 2082:                             
 2083:                             /*  k=0; ueberfluessig */
 2084:                             while (compactkey[k] == key0[k]) {
 2085: 
 2086:                                 if (compactkey[k] == g_EOL) break;
 2087: 
 2088:                                 k++;
 2089:                             }
 2090: 
 2091:                             if (compactkey[k] != g_EOL) break;	/* no descendant */
 2092:                         
 2093:                         }
 2094:                         
 2095:                         i += UNSIGN (block[i]);
 2096:                         i++;		/* skip data */
 2097:                         endadr = i;
 2098: 
 2099:                     }
 2100: 
 2101:                 }
 2102: 
 2103:                 kill_again = (endadr == offset && action != killone);	/* may be there's more to kill */
 2104: 
 2105:                 if ((begadr == 0) && (endadr == offset)) {	/* block becomes empty */
 2106: 
 2107:                     long    left,
 2108:                     right;
 2109:                     char    block0[BLOCKLEN];
 2110: 
 2111: p_empty:		/* entry if pointer block goes empty */
 2112: 
 2113:                     left = UNSIGN (block[LLPTR]) * 65536 +
 2114:                     UNSIGN (block[LLPTR + 1]) * 256 +
 2115:                     UNSIGN (block[LLPTR + 2]);
 2116:                     right = UNSIGN (block[RLPTR]) * 65536 +
 2117:                     UNSIGN (block[RLPTR + 1]) * 256 +
 2118:                     UNSIGN (block[RLPTR + 2]);
 2119: 
 2120:                     if (left) {
 2121: 
 2122:                         lseek (g->fd, hdr_offset + ((long) left * (long) (BLOCKLEN)), SEEK_SET);
 2123:                         read (g->fd, block0, BLOCKLEN);
 2124:                         
 2125:                         block0[RLPTR] = block[RLPTR];
 2126:                         block0[RLPTR + 1] = block[RLPTR + 1];
 2127:                         block0[RLPTR + 2] = block[RLPTR + 2];
 2128:                         
 2129:                         lseek (g->fd, hdr_offset + ((long) left * (long) (BLOCKLEN)), SEEK_SET);
 2130:                         write (g->fd, block0, BLOCKLEN);
 2131: 
 2132:                     }
 2133: 
 2134:                     if (right) {
 2135:                         
 2136:                         lseek (g->fd, hdr_offset + ((long) right * (long) (BLOCKLEN)), SEEK_SET);
 2137:                         read (g->fd, block0, BLOCKLEN);
 2138:                         
 2139:                         block0[LLPTR] = block[LLPTR];
 2140:                         block0[LLPTR + 1] = block[LLPTR + 1];
 2141:                         block0[LLPTR + 2] = block[LLPTR + 2];
 2142:                         
 2143:                         lseek (g->fd, hdr_offset + ((long) right * (long) (BLOCKLEN)), SEEK_SET);
 2144:                         write (g->fd, block0, BLOCKLEN);
 2145: 
 2146:                     }
 2147: 
 2148:                     b_free (g->fd, blknbr);	/* modify free list */
 2149:                     
 2150:                     /* delete pointer */
 2151:                     /**************************/
 2152:                     {
 2153:                         long    trxsav;
 2154:                         long    freecnt;
 2155: 
 2156:                         trxsav = trx;
 2157: 
 2158:                         blknbr = traceblk[--trx];
 2159:                         addr = traceadr[trx];
 2160: 
 2161:                         lseek (g->fd, hdr_offset + ((long) (blknbr) * (long) (BLOCKLEN)), SEEK_SET);
 2162:                         read (g->fd, block, BLOCKLEN);
 2163:                         offset = UNSIGN (block[OFFS]) * 256 +
 2164:                         UNSIGN (block[OFFS + 1]);
 2165:                         freecnt = UNSIGN (block[addr]) + 2 + PLEN;
 2166: 
 2167:                         /* delete key */
 2168:                         offset -= freecnt;
 2169:                         
 2170:                         if (offset == 0) {	/* pointer block went empty */
 2171: 
 2172:                             if (blknbr == ROOT) {	/* global went empty */
 2173: 
 2174:                                 lseek (g->fd, hdr_offset + 0L, SEEK_SET);
 2175:                         
 2176:                                 /* note : UNIX does not tell other    */
 2177:                                 block[BTYP] = EMPTY;	/* jobs that a file has been unlinked */
 2178:                         
 2179:                                 /* as long as they keep it open.      */
 2180:                                 /* so we mark this global as EMPTY    */
 2181:                                 write (g->fd, block, BLOCKLEN);
 2182:                                 gbl_close (g);
 2183:                                 unlink (filnam);
 2184: 
 2185:                                 gbl_unlock (g);
 2186: 
 2187:                                 olddes[inuse] = 0;
 2188:                                 oldfil[inuse][0] = NUL;
 2189:                                 usage[inuse] = 0;
 2190:                                 
 2191:                                 return;
 2192: 
 2193:                             }
 2194: 
 2195:                             goto p_empty;	/* clear pointer block */
 2196: 
 2197:                         }
 2198: 
 2199:                         block[OFFS] = offset / 256;
 2200:                         block[OFFS + 1] = offset % 256;
 2201: 
 2202:                         stcpy0 (&block[addr], &block[addr + freecnt], (long) (offset - addr));
 2203:                         
 2204:                         for (i = offset; i < offset + freecnt; block[i++] = 0);
 2205: 
 2206:                         lseek (g->fd, hdr_offset + ((long) (blknbr) * (long) (BLOCKLEN)), SEEK_SET);
 2207:                         write (g->fd, block, BLOCKLEN);
 2208: 
 2209:                         if (addr == 0) {	/* update of pointer */
 2210:                             traceadr[trx] = 0;
 2211:                             
 2212:                             update (g, &block[2], (long) UNSIGN (block[0]));
 2213:                         }
 2214: 
 2215:                         trx = trxsav;
 2216: 
 2217:                     }
 2218: 
 2219:                     if (kill_again) goto k_again;
 2220: 
 2221:                     break;
 2222:                 }
 2223: 
 2224:                 i = begadr;
 2225:                 j = endadr;
 2226: 
 2227:                 while (j < offset) block[i++] = block[j++];
 2228:                 while (i < offset) block[i++] = 0;
 2229:                 
 2230:                 /** clear rest */
 2231:                 offset += (begadr - endadr);
 2232:                 if (begadr < offset && block[begadr + 1]) {		/* new key_offset for next entry */
 2233:                     i = block[begadr];
 2234:                     j = block[begadr + 1];
 2235:                     k = 0;
 2236:                     if (begadr)
 2237:                     while (key0[k] == key1[k])
 2238:                     k++;		/* new key_offset */
 2239:                     if (k < j) {
 2240:                     ch = j - k;		/* space requirement */
 2241:                     block[begadr] = i + ch;	/* new key_length */
 2242:                     block[begadr + 1] = k;	/* new key_offset */
 2243:                     i = offset;
 2244:                     j = i + ch;
 2245:                     offset = j;
 2246:                     begadr++;
 2247:                     while (i > begadr)
 2248:                     block[j--] = block[i--];
 2249:                     stcpy0 (&block[begadr + 1], &key0[k], ch);
 2250:                     }
 2251:                 }
 2252:                 block[OFFS] = offset / 256;
 2253:                 block[OFFS + 1] = offset % 256;
 2254:                 lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2255:                 write (g->fd, block, BLOCKLEN);
 2256:                 if (addr < 3) {		/* update of pointer */
 2257:                 traceadr[trx] = 0;
 2258:                 update (g, &block[2], (long) UNSIGN (block[0]));
 2259:                 }
 2260:             }
 2261: 
 2262:             if (kill_again) goto k_again;
 2263: 
 2264:             break;
 2265: 
 2266: zinv:
 2267: 
 2268:             {
 2269:                 long    len;
 2270:                 int     ch0;
 2271:                 char    scratch[256];
 2272:                 char    key0[256];
 2273: 
 2274:                 if (addr <= 0) {		/* look in previous block */
 2275: 
 2276:                     if ((blknbr = UNSIGN (block[LLPTR]) * 65536 + UNSIGN (block[LLPTR + 1]) * 256 + UNSIGN (block[LLPTR + 2])) == 0) {
 2277:                         data[0] = EOL1;
 2278:                         goto quit;
 2279:                     }			/* no previous block */
 2280:                     
 2281:                     lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2282:                     read (g->fd, block, BLOCKLEN);
 2283:                     
 2284:                     addr = UNSIGN (block[OFFS]) * 256 +
 2285:                     UNSIGN (block[OFFS + 1]);
 2286: 
 2287:                 }
 2288: 
 2289:                 i = 0;
 2290: 
 2291:                 while (i < addr) {		/* compute offset complete key */
 2292: 
 2293:                     len = UNSIGN (block[i++]);
 2294:                     len += (j = UNSIGN (block[i++]));
 2295:                     
 2296:                     while (j < len) key0[j++] = block[i++];
 2297: 
 2298:                     key0[j] = g_EOL;
 2299:                     j1 = i;
 2300:                     i += UNSIGN (block[i]);
 2301:                     i++;			/* skip data */
 2302: 
 2303:                 }
 2304: 
 2305:                 /* save data value for inspection with $V(111) */
 2306:                 j = UNSIGN (block[j1++]);
 2307: 
 2308:                 stcpy0 (g_o_val, &block[j1], j);	/* get value */
 2309:                 g_o_val[j] = EOL;		/* append EOL */
 2310: 
 2311:                 i = 0;
 2312:                 j = 0;
 2313: 
 2314:                 while ((scratch[j++] = UNSIGN (key0[i++])) != g_EOL);
 2315: 
 2316:                 /* count subscripts of key */
 2317:                 i = 0;
 2318:                 j1 = 0;
 2319:                 
 2320:                 while (i < keyl) {
 2321:                 
 2322:                     if (compactkey[i++] & 01) {
 2323:                         j1++;
 2324:                     }
 2325:                 
 2326:                 }
 2327: 
 2328:                 i = 0;
 2329:                 j = 0;
 2330:                 k = 0;
 2331: 
 2332:                 while (i < keyl) {
 2333: 
 2334:                     if (scratch[i] != compactkey[j++]) {
 2335:                         k++;
 2336:                         break;
 2337:                     }
 2338: 
 2339:                     if (scratch[i++] & 01) k++;
 2340: 
 2341:                 }
 2342: 
 2343:                 if (k < j1) {
 2344:                     data[0] = EOL1;
 2345:                     g_o_val[0] = EOL;
 2346: 
 2347:                     goto quit;
 2348:                 }
 2349: 
 2350:                 while (--i >= 0) {
 2351:                     if ((scratch[i] & 01)) break;  
 2352:                 }
 2353: 
 2354:                 i++;
 2355:                 j = 0;
 2356:                 
 2357:                 while ((ch = UNSIGN (scratch[i++])) != g_EOL) {
 2358: 
 2359:                     ch0 = (ch >= SP ? (ch >> 1) :	/* 'string' chars */
 2360:                     (ch < 20 ? (ch >> 1) + '0' :	/* 0...9          */
 2361:                     (ch >> 1) + SP));	/* '.' or '-'     */
 2362:                     
 2363:                     if (ch0 == DEL) {
 2364: 
 2365:                         if (((ch = UNSIGN (scratch[i++])) >> 1) == DEL) {                            
 2366:                             ch0 += DEL;
 2367:                             ch = UNSIGN (scratch[i++]);
 2368:                         }
 2369: 
 2370:                         ch0 += (ch >> 1);
 2371: 
 2372:                     }
 2373: 
 2374:                     data[j++] = ch0;
 2375:                     
 2376:                     if (ch & 01) break;
 2377:                 
 2378:                 }
 2379:                 
 2380:                 data[j] = EOL1;
 2381:                 
 2382:                 if (j == 0) break;
 2383:                 
 2384:                 ordercounter++;
 2385:                 
 2386:                 if (ordercnt++ < (-1)) {	/* repeated backward scanning */
 2387:                 
 2388:                     if (ch != g_EOL) scratch[i] = g_EOL;
 2389: 
 2390:                     stcpy0 (compactkey, scratch, i + 1);
 2391:                     
 2392:                     compactkey[i - 1] |= 01;
 2393:                     keyl = i;
 2394:                     
 2395:                     goto k_again;
 2396: 
 2397:                 }
 2398: 
 2399:             }
 2400: 
 2401:             break;
 2402: 
 2403: 
 2404:         case zdata:			/* nonstandard data function */
 2405: 
 2406:             {
 2407:                 long counties[128];
 2408:                 char key0[256];
 2409:                 int icnt, icnt0, len;
 2410: 
 2411:                 i = 0;
 2412: 
 2413:                 while (i < 128) counties[i++] = 0L;	/* init count;  */
 2414:                 
 2415:                 if (found == 2) {		/* ... advance to next entry */
 2416:                     addr += UNSIGN (block[addr]);
 2417:                     addr += 2;		/* skip key */
 2418:                     addr += UNSIGN (block[addr]);
 2419:                     addr++;			/* skip data */
 2420: 
 2421:                     counties[0] = 1L;
 2422:                 }
 2423: 
 2424:                 offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
 2425:                 icnt = 0;
 2426:                 i = 0;
 2427: 
 2428:                 while ((ch = compactkey[i++]) != g_EOL) {
 2429:                 
 2430:                     if (ch & 01) {
 2431:                         icnt++;
 2432:                     }
 2433:                 
 2434:                 }
 2435:                 
 2436:                 len = i - 1;
 2437:                 i = 0;
 2438:                 
 2439:                 while (i < addr) {		/* compute offset complete key */
 2440: 
 2441:                     icnt0 = UNSIGN (block[i++]);
 2442:                     icnt0 += (j = UNSIGN (block[i++]));
 2443:                     
 2444:                     while (j < icnt0) key0[j++] = block[i++];
 2445:                     
 2446:                     key0[j] = g_EOL;                    
 2447:                     i += UNSIGN (block[i]);
 2448:                     
 2449:                     i++;			/* skip data */
 2450: 
 2451:                 }
 2452: 
 2453:                 for (;;) {			/* is it still a descendant ??? */
 2454:         
 2455:                     if (addr >= offset) {	/* look in next block */
 2456: 
 2457:                         if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
 2458:                             break;		/* no next block */
 2459:                         }
 2460: 
 2461:                         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2462:                         read (g->fd, block, BLOCKLEN);
 2463:                         
 2464:                         addr = 0;
 2465:                         offset = UNSIGN (block[OFFS]) * 256 +
 2466:                         UNSIGN (block[OFFS + 1]);
 2467: 
 2468:                     }
 2469: 
 2470:                     i = UNSIGN (block[addr++]);
 2471:                     i += (j = UNSIGN (block[addr++]));
 2472:                     
 2473:                     while (j < i) key0[j++] = block[addr++];
 2474: 
 2475:                     addr += UNSIGN (block[addr]);
 2476:                     addr++;			/* skip data */
 2477:                     icnt0 = 0;
 2478:                     i = 0;
 2479:                     
 2480:                     while (i < j) if (key0[i++] & 01)
 2481:                     
 2482:                     icnt0++;
 2483:                     
 2484:                     if (icnt0 <= icnt) break;
 2485:                     
 2486:                     i = 0;
 2487:                     
 2488:                     while (i < len) {
 2489: 
 2490:                         if (key0[i] != compactkey[i]) break;
 2491:                     
 2492:                         i++;
 2493: 
 2494:                     }
 2495: 
 2496:                     if (i < len) break;
 2497:                     
 2498:                     counties[icnt0 - icnt]++;
 2499: 
 2500:                 }
 2501: 
 2502:                 i = 128;
 2503: 
 2504:                 while (counties[--i] == 0L);
 2505: 
 2506:                 lintstr (data, counties[0]);
 2507:                 
 2508:                 j = 1;
 2509:                 tmp1[0] = ',';
 2510:                 
 2511:                 while (j <= i) {
 2512:                     lintstr (&tmp1[1], counties[j++]);
 2513:                     stcat (data, tmp1);
 2514:                 }
 2515: 
 2516:             }
 2517:             
 2518:             break;
 2519: 
 2520:         case getinc:
 2521:         
 2522:             {
 2523:                 int     setopsav;
 2524: 
 2525:                 setopsav = setop;
 2526:                 setop = '+';
 2527:                 data[0] = '1';
 2528:                 data[1] = EOL;
 2529: 
 2530:                 global  (set_sym, key, data);
 2531: 
 2532:                 setop = setopsav;
 2533:                 
 2534:                 return;
 2535:             }
 2536: 
 2537:         case killone:
 2538: 
 2539:             {
 2540:                 if (found == 2) goto killo;		/* entry found use normal kill routine */
 2541:                 
 2542:                 goto quit;
 2543:             }
 2544: 
 2545:         case merge_sym:
 2546: 
 2547:             printf("MERGE NOT IMPLEMENTED FOR GLOBALS\n");
 2548: 
 2549: #ifdef DEBUG_GBL     
 2550:     
 2551:             int loop;
 2552:     
 2553:             printf ("DEBUG MERGE: ");
 2554:             printf ("[key] is [");
 2555:     
 2556:             for (loop = 0; key[loop] != EOL; loop++) printf ("%c", (key[loop] == DELIM) ? '!' : key[loop]);
 2557:     
 2558:             printf ("]\r\n");
 2559:             printf ("[data] is [");
 2560:     
 2561:             for(loop = 0; data[loop] != EOL; loop++) printf ("%c", (data[loop] == DELIM) ? '!' : data[loop]);
 2562:     
 2563:             printf("]\r\n");    
 2564: 
 2565: #endif
 2566:             return;
 2567: 
 2568:         default:
 2569:     
 2570:             merr_raise (INVREF);			/* accidental call with wrong action code (v22-stuff) */
 2571:     }					/* end of switch */
 2572: 
 2573: quit:
 2574:     
 2575:     /* clean things up */
 2576: 
 2577:     lseek (g->fd, hdr_offset + ROOT, SEEK_SET);
 2578:     gbl_unlock (g);
 2579:     
 2580:     return;
 2581: 
 2582: 
 2583: splitd:				/* split data block in two sections */
 2584: 
 2585:     /* part of the data is taken to an other location. */
 2586:     /* old information in 'block' stored at 'blknbr' */
 2587:     /* 'addr' there I would like to insert, if possible (which is not) */
 2588:     /* 'offset' filled up to this limit */
 2589: 
 2590:     getnewblk (g->fd, &newblk);	/* get a new block */
 2591: 
 2592:     /* if we have to insert at the begin or end of a block  */
 2593:     /* we don't split - we just start a new block           */
 2594:     /* if an insert in the midst of a block, we split       */
 2595: 
 2596:     if (addr >= offset) {
 2597:         long    right,
 2598:         right1,
 2599:         right2;
 2600: 
 2601:         right = UNSIGN (block[RLPTR]);
 2602:         right1 = UNSIGN (block[RLPTR + 1]);
 2603:         right2 = UNSIGN (block[RLPTR + 2]);
 2604:         block[RLPTR] = newblk / 65536;
 2605:         block[RLPTR + 1] = newblk % 65536 / 256;
 2606:         block[RLPTR + 2] = newblk % 256;
 2607: 
 2608:         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2609:         write (g->fd, block, BLOCKLEN);
 2610:         
 2611:         block[RLPTR] = right;
 2612:         block[RLPTR + 1] = right1;
 2613:         block[RLPTR + 2] = right2;
 2614:         block[LLPTR] = blknbr / 65536;
 2615:         block[LLPTR + 1] = blknbr % 65536 / 256;
 2616:         block[LLPTR + 2] = blknbr % 256;
 2617:         offset = 0;
 2618:         addr = 0;
 2619:         blknbr = newblk;
 2620:         
 2621:         insert (g, compactkey, keyl, newblk);
 2622:         
 2623:         /* up-date LL-PTR of RL-block */
 2624:         if ((other = right * 65536 + right1 * 256 + right2)) {
 2625:         
 2626:             char    block0[BLOCKLEN];
 2627: 
 2628:             lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2629:             read (g->fd, block0, BLOCKLEN);
 2630:         
 2631:             block0[LLPTR] = blknbr / 65536;
 2632:             block0[LLPTR + 1] = blknbr % 65536 / 256;
 2633:             block0[LLPTR + 2] = blknbr % 256;
 2634:         
 2635:             lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2636:             write (g->fd, block0, BLOCKLEN);
 2637:         
 2638:         }
 2639:         
 2640:         goto spltex;
 2641:     }
 2642: 
 2643:     if (addr == 0) {
 2644:         long left, left1, left2;
 2645: 
 2646:         left = UNSIGN (block[LLPTR]);
 2647:         left1 = UNSIGN (block[LLPTR + 1]);
 2648:         left2 = UNSIGN (block[LLPTR + 2]);
 2649: 
 2650:         block[LLPTR] = newblk / 65536;
 2651:         block[LLPTR + 1] = newblk % 65536 / 256;
 2652:         block[LLPTR + 2] = newblk % 256;
 2653: 
 2654:         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2655:         write (g->fd, block, BLOCKLEN);
 2656:         
 2657:         block[LLPTR] = left;
 2658:         block[LLPTR + 1] = left1;
 2659:         block[LLPTR + 2] = left2;
 2660:         block[RLPTR] = blknbr / 65536;
 2661:         block[RLPTR + 1] = blknbr % 65536 / 256;
 2662:         block[RLPTR + 2] = blknbr % 256;
 2663:         offset = 0;
 2664:         blknbr = newblk;
 2665:         traceadr[trx] = (-1);		/* inhibit second update of pointers */
 2666:         
 2667:         insert (g, compactkey, keyl, newblk);
 2668:         
 2669:         if (addr < 3) {			/* update of pointer */
 2670:             traceadr[trx] = 0;
 2671:             
 2672:             update (g, compactkey, keyl);
 2673:         }
 2674: 
 2675:         /* other is ***always*** zero !!!
 2676:         * if (other=left*65536+left1*256+left2) up-date RL-PTR of LL-block
 2677:         * { char block0[BLOCKLEN];
 2678:         * lseek(filedes,(long)other*(long)(BLOCKLEN),0);
 2679:         * read(filedes,block0,BLOCKLEN);
 2680:         * block0[RLPTR  ]=blknbr/65536;
 2681:         * block0[RLPTR+1]=blknbr%65536/256;
 2682:         * block0[RLPTR+2]=blknbr%256;
 2683:         * lseek(filedes,(long)other*(long)(BLOCKLEN),0);
 2684:         * write(filedes,block0,BLOCKLEN);
 2685:         * }
 2686:         */
 2687: 
 2688:         goto spltex;
 2689: 
 2690:     } 
 2691: 
 2692:     {
 2693:         char    block0[BLOCKLEN];
 2694:         char    key0[256];
 2695:         int     newlimit;
 2696: 
 2697:         block0[BTYP] = DATA;
 2698: 
 2699:         /* now search for a dividing line                       */
 2700:         limit = (offset + needed) / 2;
 2701:         i = (offset - needed) / 2;
 2702: 
 2703:         if (addr < i) limit = i;
 2704: 
 2705:         i = 0;
 2706:         newlimit = i;
 2707: 
 2708:         while (i < limit) {
 2709: 
 2710:             newlimit = i;
 2711:             j = UNSIGN (block[i++]);	/* length of key - offset */
 2712:             k = UNSIGN (block[i++]);	/* offset into previous entry */
 2713:             j += k;
 2714:             
 2715:             while (k < j) key0[k++] = block[i++];	/* get key */
 2716:             
 2717:             key0[k] = g_EOL;
 2718:             i += UNSIGN (block[i]);
 2719:             i++;			/* skip data */
 2720: 
 2721:         }
 2722: 
 2723:         limit = newlimit;
 2724:         i = newlimit;
 2725: 
 2726:         j = i;
 2727:         i = 0;				/* copy part of old to new blk */
 2728:         
 2729:         if ((k = UNSIGN (block[j + 1])) != 0) {		/* expand key */
 2730: 
 2731:             block0[i++] = UNSIGN (block[j++]) + k;
 2732:             block0[i++] = 0;
 2733:         
 2734:             if (addr > limit) addr += k;
 2735: 
 2736:             j = 0;
 2737:             
 2738:             while (j < k) block0[i++] = key0[j++];
 2739: 
 2740:             j = limit + 2;
 2741: 
 2742:         }
 2743: 
 2744:         while (j < offset) {
 2745:             
 2746:             block0[i++] = block[j];
 2747:             block[j] = 0;
 2748:             
 2749:             j++;
 2750: 
 2751:         }
 2752: 
 2753:         while (i <= DATALIM) block0[i++] = 0;		/* clear rest of block */
 2754:         
 2755:         offset -= limit;
 2756:         
 2757:         if (k > 0) offset += k;		/* new offsets */
 2758:         
 2759:         block[OFFS] = limit / 256;
 2760:         block[OFFS + 1] = limit % 256;
 2761:         block0[OFFS] = offset / 256;
 2762:         block0[OFFS + 1] = offset % 256;
 2763: 
 2764:         if (addr <= limit) {		/* save new block away */
 2765: 
 2766:             /* update rightlink and leftlink pointers */
 2767:             other = UNSIGN (block[RLPTR]) * 65536 +
 2768:             UNSIGN (block[RLPTR + 1]) * 256 +
 2769:             UNSIGN (block[RLPTR + 2]);
 2770:             block0[RLPTR] = block[RLPTR];
 2771:             block0[RLPTR + 1] = block[RLPTR + 1];
 2772:             block0[RLPTR + 2] = block[RLPTR + 2];
 2773:             block[RLPTR] = newblk / 65536;
 2774:             block[RLPTR + 1] = newblk % 65536 / 256;
 2775:             block[RLPTR + 2] = newblk % 256;
 2776:             block0[LLPTR] = blknbr / 65536;
 2777:             block0[LLPTR + 1] = blknbr % 65536 / 256;
 2778:             block0[LLPTR + 2] = blknbr % 256;
 2779: 
 2780:             lseek (g->fd, hdr_offset + ((long) (newblk) * (long) (BLOCKLEN)), SEEK_SET);
 2781:             write (g->fd, block0, BLOCKLEN);
 2782:         
 2783:             offset = limit;
 2784:             /* insert new block in pointer structure */
 2785:         
 2786:             insert (g, &block0[2], (long) UNSIGN (block0[0]), newblk);
 2787:         
 2788:             /* up-date LL-PTR of RL-block */
 2789:             if (other != 0) {
 2790: 
 2791:                 lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2792:                 read (g->fd, block0, BLOCKLEN);
 2793: 
 2794:                 block0[LLPTR] = newblk / 65536;
 2795:                 block0[LLPTR + 1] = newblk % 65536 / 256;
 2796:                 block0[LLPTR + 2] = newblk % 256;
 2797:                 
 2798:                 lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2799:                 write (g->fd, block0, BLOCKLEN);
 2800: 
 2801:             }
 2802: 
 2803:         } 
 2804:         else {			
 2805:             /* save old block away and make new block the current block */
 2806:             /* update rightlink and leftlink pointers */
 2807:             other = UNSIGN (block[RLPTR]) * 65536 +
 2808:             UNSIGN (block[RLPTR + 1]) * 256 +
 2809:             UNSIGN (block[RLPTR + 2]);
 2810:             block0[RLPTR] = block[RLPTR];
 2811:             block0[RLPTR + 1] = block[RLPTR + 1];
 2812:             block0[RLPTR + 2] = block[RLPTR + 2];
 2813:             block[RLPTR] = newblk / 65536;
 2814:             block[RLPTR + 1] = newblk % 65536 / 256;
 2815:             block[RLPTR + 2] = newblk % 256;
 2816:             block0[LLPTR] = blknbr / 65536;
 2817:             block0[LLPTR + 1] = blknbr % 65536 / 256;
 2818:             block0[LLPTR + 2] = blknbr % 256;
 2819: 
 2820:             lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 2821:             write (g->fd, block, BLOCKLEN);
 2822:             stcpy0 (block, block0, (long) BLOCKLEN);
 2823: 
 2824:             traceadr[trx] = (addr -= limit);
 2825:             traceblk[trx] = (blknbr = newblk);
 2826:             
 2827:             /* insert new block in pointer structure */
 2828:             insert (g, &block0[2], (long) UNSIGN (block0[0]), newblk);
 2829:             
 2830:             /* up-date LL-PTR of RL-block */
 2831:             if (other != 0) {
 2832: 
 2833:                 lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2834:                 read (g->fd, block0, BLOCKLEN);
 2835:                 
 2836:                 block0[LLPTR] = newblk / 65536;
 2837:                 block0[LLPTR + 1] = newblk % 65536 / 256;
 2838:                 block0[LLPTR + 2] = newblk % 256;
 2839:                 
 2840:                 lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2841:                 write (g->fd, block0, BLOCKLEN);
 2842: 
 2843:             }
 2844: 
 2845:         }
 2846:     }
 2847: 
 2848: spltex:
 2849: 
 2850:     if (ret_to == 'n') goto s10;
 2851: 
 2852:     goto s20;
 2853: }					/* end global() */
 2854: 
 2855: /*
 2856:  * split pointer block in two sections
 2857:  *  filedes:    global file descriptor
 2858:  *  block:      old block (which is too small)
 2859:  *  addr:       addr of entry where to insert
 2860:  *  offs:       offset of block
 2861:  *  blknbr:     number of old block
 2862:  *
 2863:  *   part of the data is taken to an other location.  
 2864:  *   old information in 'block' stored at 'blknbr'
 2865:  *   'addr' there I would like to insert, if possible (which is not)
 2866:  *   'offset' filled up to this limit
 2867:  */
 2868: static void splitp (global_handle *g, char *block, long *addr, long *offs, unsigned long *blknbr)	
 2869: {
 2870: 
 2871:     char block0[BLOCKLEN];
 2872:     long limit;
 2873:     unsigned long newblk;
 2874:     unsigned long other;
 2875:     register int i, j;
 2876: 
 2877:     long hdr_offset;
 2878: 
 2879:     hdr_offset = sizeof (global_header);
 2880:     
 2881:     getnewblk (g->fd, &newblk);	/* get a new block */
 2882:     
 2883:     if (*blknbr == ROOT) {		/* ROOT overflow is special */
 2884: 
 2885:         stcpy0 (block0, block, (long) BLOCKLEN);
 2886:         
 2887:         /* clear pointers */
 2888:         block[LLPTR] = 0;
 2889:         block[LLPTR + 1] = 0;
 2890:         block[LLPTR + 2] = 0;
 2891:         block[RLPTR] = 0;
 2892:         block[RLPTR + 1] = 0;
 2893:         block[RLPTR + 2] = 0;
 2894:         
 2895:         /* old root block is a 'normal' block now */
 2896:         /* new root points to a single block */
 2897:         i = UNSIGN (block0[0]) + 2;
 2898:         block0[i++] = newblk / 65536;
 2899:         block0[i++] = newblk % 65536 / 256;
 2900:         block0[i++] = newblk % 256;
 2901:         block0[OFFS] = i / 256;
 2902:         block0[OFFS + 1] = i % 256;
 2903:         
 2904:         while (i < DATALIM) block0[i++] = 0;		/* clear rest */
 2905:         
 2906:         /* update number of blocks ! */
 2907:         i = UNSIGN (block0[NRBLK]) * 65536 +
 2908:         UNSIGN (block0[NRBLK + 1]) * 256 +
 2909:         UNSIGN (block0[NRBLK + 2]) + 1;
 2910: 
 2911:         block0[NRBLK] = i / 65536;
 2912:         block0[NRBLK + 1] = i % 65536 / 256;
 2913:         block0[NRBLK + 2] = i % 256;
 2914:         block0[BTYP] = POINTER;
 2915:         
 2916:         lseek (g->fd, hdr_offset + ROOT, SEEK_SET);
 2917:         write (g->fd, block0, BLOCKLEN);
 2918:         
 2919:         /* shift trace_stack */
 2920:         j = trx++;
 2921:         i = trx;
 2922:         
 2923:         /** if (j>=TRLIM) 'global too big' */
 2924:         while (j >= 0) {
 2925:             traceblk[i] = traceblk[j];
 2926:             traceadr[i--] = traceadr[j--];
 2927:         }
 2928: 
 2929:         traceblk[0] = 0;		/*ROOT */
 2930:         traceadr[0] = 0;
 2931:         traceblk[1] = newblk;
 2932:         *blknbr = newblk;
 2933:         
 2934:         getnewblk (g->fd, &newblk);	/* get a new block */
 2935: 
 2936:     }
 2937: 
 2938:     block0[BTYP] = block[BTYP];
 2939: 
 2940:     /* now search for a dividing line */
 2941:     i = 0;
 2942:     limit = (*offs) / 2;
 2943:     
 2944:     while (i < limit) {
 2945:         i += UNSIGN (block[i]);
 2946:         i += 2;				/* skip key */
 2947:         i += PLEN;			/* skip data */
 2948:     }
 2949: 
 2950:     /* new offsets */
 2951:     limit = i;
 2952: 
 2953:     i = (*offs) - limit;
 2954:     
 2955:     block[OFFS] = limit / 256;
 2956:     block[OFFS + 1] = limit % 256;
 2957:     block0[OFFS] = i / 256;
 2958:     block0[OFFS + 1] = i % 256;
 2959: 
 2960:     for (i = 0; i <= DATALIM; block0[i++] = 0);
 2961: 
 2962:     i = 0;
 2963:     j = limit;				/* copy part of old to new blk */
 2964:     
 2965:     while (j < (*offs)) {
 2966:         block0[i++] = block[j];
 2967:         block[j] = 0;
 2968:     
 2969:         j++;
 2970:     }
 2971: 
 2972:     if ((*addr) <= limit) {		/* save new block away */
 2973: 
 2974:         /* update rightlink and leftlink pointers */
 2975:         other = UNSIGN (block[RLPTR]) * 65536 +
 2976:         UNSIGN (block[RLPTR + 1]) * 256 +
 2977:         UNSIGN (block[RLPTR + 2]);
 2978:         block0[RLPTR] = block[RLPTR];
 2979:         block0[RLPTR + 1] = block[RLPTR + 1];
 2980:         block0[RLPTR + 2] = block[RLPTR + 2];
 2981:         block[RLPTR] = newblk / 65536;
 2982:         block[RLPTR + 1] = newblk % 65536 / 256;
 2983:         block[RLPTR + 2] = newblk % 256;
 2984:         block0[LLPTR] = (*blknbr) / 65536;
 2985:         block0[LLPTR + 1] = (*blknbr) % 65536 / 256;
 2986:         block0[LLPTR + 2] = (*blknbr) % 256;
 2987: 
 2988:         lseek (g->fd, hdr_offset + ((long) (newblk) * (long) (BLOCKLEN)), SEEK_SET);
 2989:         write (g->fd, block0, BLOCKLEN);
 2990: 
 2991:         (*offs) = limit;
 2992:         
 2993:         insert (g, &block0[2], (long) UNSIGN (block0[0]), newblk);
 2994:         
 2995:         /* up-date LL-PTR of RL-block */
 2996:         if (other != 0) {
 2997: 
 2998:             lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 2999:             read (g->fd, block0, BLOCKLEN);
 3000:             
 3001:             block0[LLPTR] = newblk / 65536;
 3002:             block0[LLPTR + 1] = newblk % 65536 / 256;
 3003:             block0[LLPTR + 2] = newblk % 256;
 3004:             
 3005:             lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 3006:             write (g->fd, block0, BLOCKLEN);
 3007: 
 3008:         }
 3009: 
 3010:     } 
 3011:     else {				/* save old block away and make new block the current block */
 3012: 
 3013:         /* update rightlink and leftlink pointers */
 3014:         other = UNSIGN (block[RLPTR]) * 65536 +
 3015:         UNSIGN (block[RLPTR + 1]) * 256 +
 3016:         UNSIGN (block[RLPTR + 2]);
 3017:         
 3018:         block0[RLPTR] = block[RLPTR];
 3019:         block0[RLPTR + 1] = block[RLPTR + 1];
 3020:         block0[RLPTR + 2] = block[RLPTR + 2];
 3021:         block[RLPTR] = newblk / 65536;
 3022:         block[RLPTR + 1] = newblk % 65536 / 256;
 3023:         block[RLPTR + 2] = newblk % 256;
 3024:         block0[LLPTR] = (*blknbr) / 65536;
 3025:         block0[LLPTR + 1] = (*blknbr) % 65536 / 256;
 3026:         block0[LLPTR + 2] = (*blknbr) % 256;
 3027: 
 3028:         (*addr) -= limit;
 3029:         (*offs) -= limit;
 3030:         
 3031:         lseek (g->fd, hdr_offset + ((long) (*blknbr) * (long) (BLOCKLEN)), SEEK_SET);
 3032:         write (g->fd, block, BLOCKLEN);
 3033:         stcpy0 (block, block0, (long) BLOCKLEN);
 3034:         
 3035:         (*blknbr) = newblk;
 3036:         
 3037:         insert (g, &block0[2], (long) UNSIGN (block0[0]), newblk);
 3038:         
 3039:         /* up-date LL-PTR of RL-block */
 3040:         if (other != 0) {
 3041: 
 3042:             lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 3043:             read (g->fd, block0, BLOCKLEN);
 3044:             
 3045:             block0[LLPTR] = newblk / 65536;
 3046:             block0[LLPTR + 1] = newblk % 65536 / 256;
 3047:             block0[LLPTR + 2] = newblk % 256;
 3048:             
 3049:             lseek (g->fd, hdr_offset + ((long) other * (long) (BLOCKLEN)), SEEK_SET);
 3050:             write (g->fd, block0, BLOCKLEN);
 3051: 
 3052:         }
 3053: 
 3054:     }
 3055: 
 3056:     return;
 3057: 
 3058: }					/* end of splitp() */
 3059: 
 3060: /* update pointer
 3061:  *  filedes:    file descriptor
 3062:  *  ins_key:    key to be inserted
 3063:  *  keyl:       length of that key
 3064:  */
 3065: static void update (global_handle *g, char *ins_key, long keyl)
 3066: {
 3067:     long offset;
 3068:     long addr;
 3069:     unsigned long blknbr;
 3070:     char block[BLOCKLEN];
 3071:     long i, j, k;
 3072:     long hdr_offset;
 3073: 
 3074:     hdr_offset = sizeof (global_header);
 3075:     
 3076:     while (traceadr[trx] == 0) {	/* update of pointer blocks necessary */
 3077: 
 3078:         if (--trx < 0) break;
 3079:         
 3080:         blknbr = traceblk[trx];
 3081:         addr = traceadr[trx];
 3082:         
 3083:         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 3084:         read (g->fd, block, BLOCKLEN);
 3085:         
 3086:         {
 3087:             long    oldkeyl;
 3088: 
 3089:             oldkeyl = UNSIGN (block[addr]);
 3090: 
 3091:             i = addr + keyl + 1;
 3092:             j = oldkeyl - keyl;
 3093:             
 3094:             offset = UNSIGN (block[OFFS]) * 256 +
 3095:             UNSIGN (block[OFFS + 1]);
 3096:             
 3097:             if (j > 0) {		/* surplus space */
 3098:             
 3099:                 k = offset;
 3100:                 offset -= j;
 3101:                 j += i;
 3102:             
 3103:                 while (i < offset) block[i++] = block[j++];
 3104:             
 3105:                 while (i < k) block[i++] = 0;	/* clear area */
 3106:             
 3107:             } 
 3108:             else if (j < 0) {		/* we need more space */
 3109:             
 3110:                 /* block too small */
 3111:                 if ((offset - j) > DATALIM) splitp (g, block, &addr, &offset, &blknbr);
 3112:                 
 3113:                 i = offset;
 3114:                 offset -= j;
 3115:                 j = offset;
 3116:                 k = addr + oldkeyl;
 3117:                 
 3118:                 while (i > k) block[j--] = block[i--];
 3119: 
 3120:             }
 3121: 
 3122:             block[OFFS] = offset / 256;
 3123:             block[OFFS + 1] = offset % 256;
 3124:             block[addr] = keyl;
 3125:             
 3126:             /* overwrite */
 3127:             i = 0;
 3128:             j = (++addr);
 3129:             block[j++] = 0;		/*!!! */
 3130:             
 3131:             while (i < keyl) block[j++] = ins_key[i++];
 3132:             
 3133:             /* block pointed to remains the same */
 3134:             lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 3135:             write (g->fd, block, BLOCKLEN);
 3136: 
 3137:         }
 3138:         
 3139:         lseek (g->fd, hdr_offset + ((long) blknbr * (long) (BLOCKLEN)), SEEK_SET);
 3140:         read (g->fd, block, BLOCKLEN);
 3141: 
 3142:     }
 3143: 
 3144:     return;
 3145: 
 3146: }					/* end of update() */
 3147: 
 3148: /* 
 3149:  * insert pointer
 3150:  *  filedes:    file descriptor
 3151:  *  ins_key:    key to be inserted
 3152:  *  key_len:    length of that key
 3153:  *  blknbr:     key points to this block
 3154:  */
 3155: static void insert (global_handle *g, char *ins_key, long key_len, unsigned long blknbr)	/* insert pointer */
 3156: {
 3157:     unsigned long blk;
 3158:     char block[BLOCKLEN];
 3159:     long trxsav;
 3160:     long offset;
 3161:     long needed;
 3162:     long addr;
 3163:     register int i, k;
 3164:     long hdr_offset;
 3165: 
 3166:     hdr_offset = sizeof (global_header);
 3167:     
 3168:     trxsav = trx--;
 3169:     blk = traceblk[trx];
 3170:     addr = traceadr[trx];
 3171: 
 3172:     lseek (g->fd, hdr_offset + ((long) (blk) * (long) (BLOCKLEN)), SEEK_SET);
 3173:     read (g->fd, block, BLOCKLEN);
 3174:     
 3175:     offset = UNSIGN (block[OFFS]) * 256 +
 3176:     UNSIGN (block[OFFS + 1]);
 3177:     
 3178:     if (traceadr[trx + 1] != (-1)) {
 3179:         addr += UNSIGN (block[addr]);
 3180:         addr += (2 + PLEN);
 3181:     }					/* advance to next entry */
 3182: 
 3183:     needed = key_len + 2 + PLEN;
 3184:     
 3185:     if ((offset + needed) > DATALIM) splitp (g, block, &addr, &offset, &blk);
 3186:     
 3187:     /*  insert key */
 3188:     i = (offset += needed);
 3189:     
 3190:     block[OFFS] = i / 256;
 3191:     block[OFFS + 1] = i % 256;
 3192:     
 3193:     while (i >= addr) {
 3194:         block[i] = block[i - needed];
 3195:         i--;
 3196:     }
 3197: 
 3198:     i = addr + 2;
 3199:     k = 0;
 3200:     
 3201:     while (k < key_len) block[i++] = ins_key[k++];
 3202:     
 3203:     block[addr] = k;
 3204:     block[addr + 1] = 0;		/* !!! */
 3205:     block[i++] = blknbr / 65536;
 3206:     block[i++] = blknbr % 65536 / 256;
 3207:     block[i] = blknbr % 256;
 3208: 
 3209:     lseek (g->fd, hdr_offset + ((long) (blk) * (long) (BLOCKLEN)), SEEK_SET);
 3210:     write (g->fd, block, BLOCKLEN);
 3211:     
 3212:     trx = trxsav;
 3213:     
 3214:     return;
 3215: }					/* end of insert() */
 3216: 
 3217: /* 
 3218:  * mark 'blknbr' as free
 3219:  *  filedes:    global file descriptor
 3220:  *  blknbr:     block to be freed
 3221:  */
 3222: static void b_free (short filedes, unsigned long blknbr)
 3223: {
 3224:     char block0[BLOCKLEN];
 3225:     unsigned long free;
 3226:     unsigned long other;
 3227:     long i;
 3228:     long offset;
 3229:     long hdr_offset;
 3230:     
 3231:     hdr_offset = sizeof (global_header);
 3232:     
 3233:     /* mark block as empty */
 3234:     lseek (filedes, hdr_offset + ((long) (blknbr) * BLOCKLEN), SEEK_SET);
 3235:     read (filedes, block0, BLOCKLEN);
 3236: 
 3237:     block0[BTYP] = EMPTY;
 3238:     
 3239:     lseek (filedes, hdr_offset + ((long) (blknbr) * BLOCKLEN), SEEK_SET);
 3240:     write (filedes, block0, BLOCKLEN);
 3241: 
 3242:     /* do we have a list of free blocks? */
 3243:     lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3244:     read (filedes, block0, BLOCKLEN);
 3245:     
 3246:     if ((free = UNSIGN (block0[FREE]) * 65536 + UNSIGN (block0[FREE + 1]) * 256 + UNSIGN (block0[FREE + 2]))) {
 3247:         
 3248:         for (;;) {
 3249:         
 3250:             lseek (filedes, hdr_offset + ((long) free * (long) BLOCKLEN), SEEK_SET);
 3251:             read (filedes, block0, BLOCKLEN);
 3252: 
 3253:             other = UNSIGN (block0[RLPTR]) * 65536 +
 3254:             UNSIGN (block0[RLPTR + 1]) * 256 +
 3255:             UNSIGN (block0[RLPTR + 2]);
 3256:             
 3257:             if (other == 0) break;
 3258: 
 3259:             free = other;
 3260: 
 3261:         }
 3262: 
 3263:         offset = UNSIGN (block0[OFFS]) * 256 + UNSIGN (block0[OFFS + 1]);
 3264:         
 3265:         /* if list is full, start new page */
 3266:         if (offset > (DATALIM - PLEN)) {
 3267: 
 3268:             offset -= PLEN;
 3269:             other = UNSIGN (block0[offset]) * 65536 +
 3270:             
 3271:             UNSIGN (block0[offset + 1]) * 256 +
 3272:             UNSIGN (block0[offset + 2]);
 3273:             
 3274:             block0[offset] = 0;
 3275:             block0[offset + 1] = 0;
 3276:             block0[offset + 2] = 0;
 3277:             block0[OFFS] = offset / 256;
 3278:             block0[OFFS + 1] = offset % 256;
 3279:             block0[RLPTR] = other / 65536;
 3280:             block0[RLPTR + 1] = other % 65536 / 256;
 3281:             block0[RLPTR + 2] = other % 256;
 3282:             
 3283:             lseek (filedes, hdr_offset + ((long) free * (long) BLOCKLEN), SEEK_SET);
 3284:             write (filedes, block0, BLOCKLEN);
 3285: 
 3286:             for (i = 0; i < BLOCKLEN; block0[i++] = 0);	/* clear block */
 3287:             
 3288:             block0[BTYP] = FBLK;
 3289:             block0[LLPTR] = free / 65536;
 3290:             block0[LLPTR + 1] = free % 65536 / 256;
 3291:             block0[LLPTR + 2] = free % 256;
 3292:             offset = 0;
 3293:             
 3294:             free = other;
 3295: 
 3296:         }
 3297: 
 3298:     } 
 3299:     else {
 3300: 
 3301:         getnewblk (filedes, &free);
 3302: 
 3303:         /* set FBLK free blocks pointer */
 3304:         lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3305:         read (filedes, block0, BLOCKLEN);
 3306:         
 3307:         block0[FREE] = free / 65536;
 3308:         block0[FREE + 1] = free % 65536 / 256;
 3309:         block0[FREE + 2] = free % 256;
 3310:         
 3311:         lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3312:         write (filedes, block0, BLOCKLEN);
 3313: 
 3314:         for (i = 0; i < BLOCKLEN; block0[i++] = 0);	/* clear block */
 3315: 
 3316:         block0[BTYP] = FBLK;
 3317:         offset = 0;
 3318:     }
 3319: 
 3320:     /* enter 'blknbr' */
 3321:     block0[offset++] = blknbr / 65536;
 3322:     block0[offset++] = blknbr % 65536 / 256;
 3323:     block0[offset++] = blknbr % 256;
 3324:     block0[OFFS] = offset / 256;
 3325:     block0[OFFS + 1] = offset % 256;
 3326: 
 3327:     lseek (filedes, hdr_offset + ((long) free * (long) BLOCKLEN), SEEK_SET);
 3328:     write (filedes, block0, BLOCKLEN);
 3329:     
 3330:     return;
 3331: }					/* end of b_free() */
 3332: 
 3333: /*
 3334:  * scan pointer 'block' for 'compactkey'
 3335:  *
 3336:  * 'adr' will return an adress 
 3337:  *   2  heureka; key found at adr 
 3338:  *   1  not found, adr=following entry 
 3339:  */
 3340: static void scanpblk (char *block, long *adr, long *fnd)		
 3341: {
 3342:     register int i = 0;
 3343:     register int k;
 3344:     long j, offset, len;
 3345:     char key0[256];
 3346: 
 3347:     *adr = 0;
 3348:     offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
 3349:     
 3350:     while (i < offset) {
 3351: 
 3352: #ifdef VERSNEW
 3353: 
 3354:         j = i;				/* save adress of current entry */
 3355:         len = UNSIGN (block[i++]);
 3356: 
 3357:         stcpy0 (key0, &block[++i], len);
 3358:         
 3359:         key0[len] = g_EOL;
 3360:         i += len;
 3361: 
 3362: #else
 3363: 
 3364:         j = i++;			
 3365:         len = UNSIGN (block[j]);
 3366:         k = 0;
 3367:         i++;
 3368: 
 3369:         while (k < len) key0[k++] = block[i++];
 3370:         
 3371:         key0[k] = g_EOL;
 3372: 
 3373: #endif /* VERSNEW */
 3374: 
 3375:         if (((*fnd) = g_collate (key0)) == 1) return;
 3376: 
 3377:         *adr = j;
 3378:         
 3379:         if ((*fnd) == 2) return;
 3380: 
 3381:         i += PLEN;
 3382: 
 3383:     }
 3384: 
 3385:     return;
 3386: 
 3387: }					/* end of scanpblk() */
 3388: 
 3389: /*
 3390:  * scan 'block' for 'compactkey'
 3391:  *  same stuff as scanpblk for the params.
 3392:  */
 3393: static void scandblk (char *block, long *adr, long *fnd)		
 3394: {
 3395:     register int i = 0;
 3396:     register int k;
 3397:     long offset, len;
 3398:     char key0[256];
 3399: 
 3400:     offset = UNSIGN (block[OFFS]) * 256 +
 3401:     UNSIGN (block[OFFS + 1]);
 3402:     
 3403:     while (i < offset) {
 3404:     
 3405: #ifdef VERSNEW
 3406: 
 3407:         *adr = i;
 3408: 
 3409:         len = UNSIGN (block[i++]);
 3410:         k = UNSIGN (block[i++]);
 3411:         
 3412:         stcpy0 (&key0[k], &block[i], len);
 3413:         
 3414:         key0[k + len] = g_EOL;
 3415:         i += len;
 3416: 
 3417: #else
 3418: 
 3419:         *adr = i++;
 3420:         
 3421:         len = UNSIGN (block[*adr]) + (k = UNSIGN (block[i++]));
 3422:     
 3423:         while (k < len) key0[k++] = block[i++];
 3424:     
 3425:         key0[k] = g_EOL;
 3426: 
 3427: #endif /* VERSNEW */
 3428: 
 3429:         if (((*fnd) = g_collate (key0)) != 0) return;
 3430:         
 3431:         i += UNSIGN (block[i]);
 3432:         
 3433:         i++;				/* skip data */
 3434:     
 3435:     }
 3436:     
 3437:     *adr = i;
 3438:     
 3439:     return;
 3440: 
 3441: }					/* end of scandblk() */
 3442: 
 3443: /* 
 3444:  * get a new block
 3445:  *  filedes:    global file descriptor
 3446:  *  blknbr:     number of new block
 3447:  */
 3448: static void getnewblk (int filedes, unsigned long *blknbr)
 3449: {
 3450:     char nblock[BLOCKLEN];
 3451:     unsigned long freeblks, no_of_blks;
 3452:     long other;
 3453:     long offset;
 3454:     long hdr_offset;
 3455: 
 3456:     hdr_offset = sizeof (global_header);
 3457:     
 3458:     lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3459:     read (filedes, nblock, BLOCKLEN);
 3460: 
 3461:     freeblks = UNSIGN (nblock[FREE]) * 65536 + UNSIGN (nblock[FREE + 1]) * 256 + UNSIGN (nblock[FREE + 2]);
 3462:     no_of_blks = UNSIGN (nblock[NRBLK]) * 65536 + UNSIGN (nblock[NRBLK + 1]) * 256 + UNSIGN (nblock[NRBLK + 2]);
 3463:     
 3464:     if (freeblks) {
 3465:         
 3466:         lseek (filedes, hdr_offset + ((long) (freeblks) * BLOCKLEN), SEEK_SET);
 3467:         read (filedes, nblock, BLOCKLEN);
 3468:         
 3469:         offset = UNSIGN (nblock[OFFS]) * 256 + UNSIGN (nblock[OFFS + 1]);
 3470: 
 3471:         if (offset == 0) {		/* free list is empty. return free list blk as new block. */
 3472: 
 3473:             *blknbr = freeblks;
 3474:             other = UNSIGN (nblock[RLPTR]) * 65536 + UNSIGN (nblock[RLPTR + 1]) * 256 + UNSIGN (nblock[RLPTR + 2]);
 3475:             
 3476:             /* update RL-block, if any */
 3477:             if (other) {
 3478: 
 3479:                 lseek (filedes, hdr_offset + ((long) (other) * BLOCKLEN), SEEK_SET);
 3480:                 read (filedes, nblock, BLOCKLEN);
 3481:                 
 3482:                 nblock[LLPTR] = 0;
 3483:                 nblock[LLPTR + 1] = 0;
 3484:                 nblock[LLPTR + 2] = 0;
 3485:                 
 3486:                 lseek (filedes, hdr_offset + ((long) (other) * BLOCKLEN), SEEK_SET);
 3487:                 write (filedes, nblock, BLOCKLEN);
 3488: 
 3489:             }
 3490: 
 3491:             /* update ROOT block */
 3492:             lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3493:             read (filedes, nblock, BLOCKLEN);
 3494:             
 3495:             nblock[FREE] = other / 65536;
 3496:             nblock[FREE + 1] = other % 65536 / 256;
 3497:             nblock[FREE + 2] = other % 256;
 3498:             
 3499:             lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3500:             write (filedes, nblock, BLOCKLEN);
 3501:             
 3502:             return;
 3503: 
 3504:         }
 3505: 
 3506:         offset -= PLEN;
 3507:         *blknbr = UNSIGN (nblock[offset]) * 65536 + UNSIGN (nblock[offset + 1]) * 256 + UNSIGN (nblock[offset + 2]);
 3508:         nblock[offset] = 0;
 3509:         nblock[offset + 1] = 0;
 3510:         nblock[OFFS] = offset / 256;
 3511:         nblock[OFFS + 1] = offset % 256;
 3512:         
 3513:         lseek (filedes, hdr_offset + ((long) (freeblks) * BLOCKLEN), SEEK_SET);
 3514:         write (filedes, nblock, BLOCKLEN);
 3515:         
 3516:         return;
 3517: 
 3518:     }
 3519: 
 3520:     /* else ** freeblk==0 ** */
 3521:     no_of_blks++;
 3522:     nblock[NRBLK] = no_of_blks / 65536;
 3523:     nblock[NRBLK + 1] = no_of_blks % 65536 / 256;
 3524:     nblock[NRBLK + 2] = no_of_blks % 256;
 3525:     
 3526:     lseek (filedes, hdr_offset + ROOT, SEEK_SET);
 3527:     write (filedes, nblock, BLOCKLEN);
 3528:     
 3529:     *blknbr = no_of_blks;
 3530:     
 3531:     for (;;) {
 3532: 
 3533:         errno = 0;
 3534:         
 3535:         lseek (filedes, hdr_offset + ((long) (no_of_blks) * BLOCKLEN), SEEK_SET);
 3536:         write (filedes, nblock, BLOCKLEN);
 3537:         
 3538:         if (errno == 0) break;
 3539: 
 3540:         panic ();
 3541: 
 3542:     }
 3543: 
 3544:     return;
 3545: 
 3546: }					/* end of getnewblk() */
 3547: 
 3548: /*
 3549:  * return TRUE if 't' follows 'compactkey' in MUMPS collating sequence 
 3550:  */
 3551: static short int g_collate (char *t)
 3552: {
 3553:     char *s = compactkey;
 3554:     register int chs = *s;
 3555:     register int cht = *t;
 3556:     register int tx = 0;
 3557:     register int sx;
 3558:     short dif;
 3559: 
 3560:     /* the empty one is the leader! */
 3561:     if (chs == g_EOL) {
 3562: 
 3563:         if (cht == g_EOL) return 2;
 3564:         
 3565:         return TRUE;
 3566: 
 3567:     }
 3568: 
 3569:     if (cht == g_EOL) return FALSE;
 3570: 
 3571:     while (cht == s[tx]) {
 3572: 
 3573:         if (cht == g_EOL) return 2;
 3574:         
 3575:         cht = t[++tx];
 3576: 
 3577:     }					/* (s==t) */
 3578: 
 3579:     chs = s[tx];
 3580:     
 3581:     if (chs == OMEGA) return FALSE;
 3582:     if (chs == ALPHA) return cht != g_EOL;
 3583:     if (chs == g_EOL && t[tx - 1] & 01) return TRUE;
 3584:     if (cht == g_EOL && s[tx - 1] & 01) return FALSE;
 3585: 
 3586:     if (tx > 0) {
 3587: 
 3588:         tx--;
 3589:         
 3590:         while ((t[tx] & 01) == 0) {
 3591:         
 3592:             tx--;
 3593:         
 3594:             if (tx < 0) break;
 3595: 
 3596:         }
 3597: 
 3598:         tx++;
 3599: 
 3600:     }
 3601: 
 3602:     chs = s[tx];
 3603:     cht = t[tx];
 3604: 
 3605:     if (UNSIGN (chs) <= POINT) {	/* then come numerics */
 3606: 
 3607:         if (UNSIGN (cht) > POINT) return UNSIGN (cht) != g_EOL;
 3608: 
 3609:         /* both are numeric! now compare numeric values */
 3610: 
 3611:         if (chs == MINUS) {
 3612:             if (cht != MINUS) return TRUE;
 3613:         } 
 3614:         else {
 3615:             if (cht == MINUS) return FALSE;
 3616:         }
 3617: 
 3618:         if (chs == 1 && cht == POINT) return TRUE;
 3619:         if (cht == 1 && chs == POINT) return FALSE;
 3620: 
 3621:         dif = sx = tx;
 3622:         
 3623:         while (s[sx] != POINT) {
 3624:             if (s[sx++] & 01) break;
 3625:         }
 3626: 
 3627:         while (t[tx] != POINT) {
 3628:             if (t[tx++] & 01) break;
 3629:         }
 3630: 
 3631:         if (tx > sx) return cht != MINUS;
 3632:         if (tx < sx) return cht == MINUS;
 3633:         
 3634:         tx = dif;
 3635:         while ((cht >> 1) == (chs >> 1)) {
 3636:             
 3637:             if (cht & 01) return t[dif] == MINUS;
 3638:             if (chs & 01) return t[dif] != MINUS;
 3639:             
 3640:             chs = s[++tx];
 3641:             cht = t[tx];
 3642: 
 3643:         }
 3644: 
 3645:         return (((cht >> 1) > (chs >> 1)) == (t[dif] != MINUS)) && (t[tx] != s[tx]);
 3646: 
 3647:     }
 3648: 
 3649:     if (UNSIGN (cht) <= POINT) return FALSE;
 3650: 
 3651:     while ((dif = (UNSIGN (cht) >> 1) - (UNSIGN (chs) >> 1)) == 0) {	/* ASCII collating */
 3652:         
 3653:         if ((cht & 01) && ((chs & 01) == 0)) return FALSE;
 3654:         if ((chs & 01) && ((cht & 01) == 0)) return TRUE;
 3655:         
 3656:         chs = s[++tx];
 3657:         cht = t[tx];
 3658: 
 3659:     }
 3660: 
 3661:     if (chs == g_EOL) return TRUE;
 3662:     if (cht == g_EOL) return FALSE;
 3663:     
 3664:     return dif > 0;
 3665: 
 3666: }					/* end g_collate() */
 3667: 
 3668: /*
 3669:  * test whether 'str' is canonical
 3670:  */
 3671: //static short int g_numeric (char *str)
 3672: short g_numeric (char *str)
 3673: {
 3674:     register int ptr = 0, ch;
 3675:     register int point = 0;
 3676:     
 3677:     if (str[0] == '-') {
 3678:         if ((ch = str[++ptr]) == EOL || (ch == DELIM) || (ch == '0')) return FALSE;
 3679:     } 
 3680:     else if (str[0] == '0') {
 3681:     
 3682:         if ((ch = str[ptr + 1]) == EOL || ch == DELIM) return TRUE;
 3683: 
 3684:         return FALSE;			/* leading zero */
 3685:     }
 3686: 
 3687:     while ((ch = str[ptr++]) != EOL && ch != DELIM) {
 3688:         
 3689:         if (ch > '9') return FALSE;
 3690:         
 3691:         if (ch < '0') {
 3692:             
 3693:             if (ch != '.') return FALSE;
 3694:             if (point) return FALSE;		/* multiple points */
 3695:         
 3696:             point = TRUE;
 3697: 
 3698:         }
 3699: 
 3700:     }
 3701: 
 3702:     if (point) {
 3703: 
 3704:         ch = str[ptr - 2];
 3705:         
 3706:         if (ch == '0' || ch == '.') return FALSE;
 3707: 
 3708:     }
 3709: 
 3710:     return TRUE;
 3711: 
 3712: }					/* end g_numeric() */
 3713: 
 3714: 
 3715: /* DEPRECATED: use gbl_close_all() instead */
 3716: void close_all_globals (void)
 3717: {					
 3718:     gbl_close_all ();
 3719:     
 3720:     return;
 3721: }					/* end close_all_globals() */
 3722: 
 3723: static void panic (void)
 3724: {
 3725:     printf ("write failed\r\n");
 3726:     
 3727:     printf ("\033[s\033[25H\033[5;7mwrite needs more disk space immediately\007");
 3728:     sleep (1);
 3729:     printf ("\033[m\007\033[2K\033[u");
 3730: 
 3731:     /* restore screen 'cause system messed up screen */
 3732: 
 3733: #ifdef NOWRITEM
 3734: 
 3735:     write_m ("\033[4~\201");
 3736: 
 3737: #endif /* NOWRITEM */
 3738: 
 3739:     return;
 3740: 
 3741: }					/* end panic() */
 3742: 
 3743: 
 3744: void gbl_dump_stat(void)
 3745: {
 3746:     global_handle *g;
 3747:     int ct;
 3748:     int miss_pct;
 3749:     int hit_pct;
 3750:     unsigned long access_total;   
 3751:     unsigned long hit_total;
 3752:     
 3753:     printf ("\r\nFreeM Global Statistics [PID %d]\r\n\r\n", pid);
 3754: 
 3755:     printf ("%-20s%-10s%-12s%-20s%-10s%s\r\n", "GLOBAL", "USECT", "SLOW PTHCT", "AGE", "LAST BLK", "FILE");
 3756:     printf ("%-20s%-10s%-12s%-20s%-10s%s\r\n", "======", "=====", "==========", "===", "========", "====");
 3757: 
 3758:     access_total = 0;
 3759:     ct = 0;
 3760:     for (g = global_handles_head; g != NULL; g = g->next) {
 3761:         printf ("%-20s%-10d%-12d%-20d%-10d%s\r\n",
 3762:                 g->global_name,
 3763:                 g->use_count,
 3764:                 g->cache_misses,
 3765:                 g->age,
 3766:                 g->last_block,
 3767:                 g->global_path);
 3768:         ct++;
 3769:         access_total += g->use_count;      
 3770:     }
 3771:     if (!ct) printf ("<no globals opened in this pid>\r\n");
 3772: 
 3773:     hit_total = access_total - gbl_cache_misses;
 3774:     miss_pct = (gbl_cache_misses * 100) / access_total;
 3775:     hit_pct = (hit_total * 100) / access_total;
 3776:     
 3777:     printf ("\r\nTotal accesses:      %ld\r\n", access_total);
 3778:     printf ("Fast path hits       %ld\t(%d%%)\r\n", hit_total, hit_pct);
 3779:     printf ("Fast path misses:    %ld\t(%d%%)\r\n", gbl_cache_misses, miss_pct);    
 3780: }

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