Annotation of freem/src/global_bltin.c, revision 1.20

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

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