File:  [Coherent Logic Development] / freem / src / global_bltin.c
Revision 1.17: download - view: text, annotated - select for diffs
Fri Apr 11 14:21:03 2025 UTC (11 months, 2 weeks ago) by snw
Branches: MAIN
CVS tags: HEAD
Make all but one of the read/write calls in global_bltin use gbl_read_block or gbl_write_block

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

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