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