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