/*
* $Id: fma_globals.c,v 1.5 2025/03/22 18:43:54 snw Exp $
* fmadm - globals
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: fma_globals.c,v $
* Revision 1.5 2025/03/22 18:43:54 snw
* Make STRLEN 255 chars and add BIGSTR macro for larger buffers
*
* Revision 1.4 2025/03/09 19:14:25 snw
* First phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "fmadm.h"
void gl (char *global, short kf, short df, short nr, int chop);
int gverify (char *gpath);
static short int g_collate (); /* if 't' follows 's' in MUMPS collating */
int key_check (char *key);
void check (unsigned long blknbr);
static short int g_collate (char s[], char t[]); /* if 't' follows 's' in MUMPS collating */
void show (char key[]);
/* global variables for gverify */
short filedes; /* file descriptor */
char block[MAXLEV][BLOCKLEN]; /* block to be read */
char *blck; /* dto. as pointer */
unsigned long llink[MAXLEV]; /* left link pointers */
unsigned long rlink[MAXLEV]; /* right link pointers */
short offsets[MAXLEV]; /* offsets */
short type[MAXLEV]; /* block type */
extern short level; /* current level */
unsigned long no_of_blks; /* number of blocks */
unsigned long freeblks; /* free blocks list */
char key[256]; /* current key in pointer block scan */
short exstat = 0; /* exit status */
void showpath (); /* display path of pointers */
/* end of global variables for gverify */
int fma_globals_list (int optc, char **opts)
{
DIR *dir;
struct dirent *ent;
char filename[PATHLEN];
int ct = 0;
printf ("\nFreeM Global Listing\n");
printf ("--------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Global Path: %s\n\n", fma_global_path);
if ((dir = opendir (fma_global_path)) == NULL) {
fprintf (stderr, "fmadm: could not open global directory %s\n", fma_global_path);
return 1;
}
while ((ent = readdir (dir)) != NULL) {
strncpy (filename, ent->d_name, PATHLEN - 1);
if (filename[0] == '^' && filename[1] != '$') {
printf (" %s\n", filename);
ct++;
}
}
printf ("\n\n - %d globals found\n\n", ct);
closedir (dir);
return 0;
}
int fma_globals_examine (int optc, char **opts)
{
DIR *dir;
struct dirent *ent;
char gpath[PATHLEN];
int i;
int ct = 0;
if ((dir = opendir (fma_global_path)) == NULL) {
fprintf (stderr, "fmadm: could not open global directory %s\n", fma_global_path);
return 1;
}
printf ("\nFreeM Global Examine\n");
printf ("--------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Global Path: %s\n", fma_global_path);
printf ("Globals Selected: ");
if (optc > 1) {
for (i = fma_base_opt; i <= optc; i++) {
printf ("%s ", opts[i]);
}
printf ("\n\n");
}
else {
printf ("[ENTIRE NAMESPACE]\n\n");
}
if (optc > 1) {
for (i = fma_base_opt; i < optc; i++) {
snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
gl (gpath, FALSE, FALSE, FALSE, strlen (fma_global_path));
ct++;
}
}
else {
while ((ent = readdir (dir)) != NULL) {
strncpy (gpath, ent->d_name, PATHLEN - 1);
if (gpath[0] == '^' && gpath[1] != '$') {
snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, ent->d_name);
gl (gpath, FALSE, FALSE, FALSE, strlen (fma_global_path));
ct++;
}
}
}
printf ("\n\n");
printf (" - %d globals examined\n\n", ct);
return 0;
}
int fma_globals_remove (int optc, char **opts)
{
char gpath[PATHLEN];
int i;
int ct = 0;
int er = 0;
int tot = 0;
printf ("\nFreeM Global Removal\n");
printf ("--------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Global Path: %s\n\n", fma_global_path);
for (i = fma_base_opt; i < optc; i++) {
printf ("%-10s\t", opts[i]);
snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
if (unlink (gpath) == -1) {
printf ("[FAIL]\n");
er++;
}
else {
printf ("[OK]\n");
ct++;
}
tot++;
}
printf ("\nRemoved %d globals [%d errors/%d attempted]\n\n", ct, er, tot);
return 0;
}
int fma_globals_verify (int optc, char **opts)
{
DIR *dir;
struct dirent *ent;
char gpath[PATHLEN];
int i;
int ct = 0;
if ((dir = opendir (fma_global_path)) == NULL) {
fprintf (stderr, "fmadm: could not open global directory %s\n", fma_global_path);
return 1;
}
printf ("\nFreeM Global Verify\n");
printf ("-------------------\n\n");
printf ("Namespace: %s\n", fma_namespace);
printf ("Global Path: %s\n", fma_global_path);
printf ("Globals Selected: ");
if (optc > fma_base_opt) {
for (i = fma_base_opt; i < optc; i++) {
printf ("%s ", opts[i]);
}
printf ("\n\n");
}
else {
printf ("[ENTIRE NAMESPACE]\n\n");
}
if (optc > fma_base_opt) {
for (i = fma_base_opt; i < optc; i++) {
snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
exstat = 0;
gverify (gpath);
printf ("\n\t%d error(s) in %s\n", exstat, gpath);
ct++;
}
}
else {
while ((ent = readdir (dir)) != NULL) {
strncpy (gpath, ent->d_name, PATHLEN - 1);
if (gpath[0] == '^') {
snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, ent->d_name);
exstat = 0;
gverify (gpath);
printf ("\n\t%d errors in %s\n", exstat, gpath);
ct++;
}
}
}
printf ("\n\n");
printf (" - %d globals verified\n\n", ct);
return 0;
}
/* PRIVATE FUNCTIONS */
/***
* gl(): list global
*
* global: name of global
* kf: key flag
* df: data flag
* nr: naked reference flag
*/
void gl (char *global, short kf, short df, short nr, int chop)
{
short filedes; /* file descriptor */
char block[BLOCKLEN]; /* block to be read */
char key[512];
char prevkey[512]; /* previous key */
char data[1024]; /* if data has CTRLs it may become */
/* so long */
unsigned long blknbr;
short offset;
short length;
short koffs;
short dkf = TRUE;
short CtrlFlag;
short n, k1;
register int i, j, k, ch;
if ((filedes = open (global, 0)) == -1) {
printf ("%s: cannot open\012\015", global);
return;
}
if (kf == FALSE && df == FALSE) {
kf = TRUE;
df = TRUE;
}
else {
dkf = FALSE;
}
blknbr = ROOT;
prevkey[0] = 0;
prevkey[1] = 0;
prevkey[2] = 0;
for (;;) {
lseek (filedes, blknbr * BLOCKLEN, 0);
if (read (filedes, block, BLOCKLEN) == 0) {
fprintf (stderr, "\015*** something wrong ***\033[K\n\r");
exit (0);
}
if (block[BTYP] == DATA) goto first;
i = UNSIGN (block[0]) + 2;
blknbr = UNSIGN (block[i]) * 65536 + UNSIGN (block[i + 1]) * 256 + UNSIGN (block[i + 2]);
}
again:
if (blknbr == 0) {
close (filedes);
return;
}
lseek (filedes, blknbr * 1024L, 0);
read (filedes, block, BLOCKLEN);
first:
offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]);
i = 0;
while (i < offset) {
length = UNSIGN (block[i++]);
k = koffs = UNSIGN (block[i++]);
if ((i + length) > offset) break;
for (j = 0; j < length; j++) key[k++] = block[i++];
key[k] = g_EOL;
{
short ch0, i, j, k;
j = 0;
i = 0;
data[j++] = '(';
k = 1;
while ((ch = UNSIGN (key[i++])) != g_EOL) {
if (k) {
k = 0;
if (ch > SP) data[j++] = '"';
}
ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
(ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
(ch >> 1) + SP)); /* '.' or '-' */
if (ch0 == DEL) {
if ((ch0 = (UNSIGN (key[i++]) >> 1)) == DEL) {
ch0 = (UNSIGN (key[i++]) >> 1) + DEL;
}
ch0 += DEL;
data[j] = '<';
data[++j] = '0' + ch0 / 100;
data[++j] = '0' + (ch0 % 100) / 10;
data[++j] = '0' + ch0 % 10;
data[++j] = '>';
}
else {
data[j] = ch0;
}
if (data[j++] == '"') data[j++] = '"';
if (ch & 01) {
if (ch > SP) data[j++] = '"';
data[j++] = ',';
k = 1;
}
}
data[j--] = 0;
data[j] = ')';
if (j == 0) data[0] = 0;
while (j >= 0) {
if ((ch = data[--j]) < SP || ch >= DEL) break;
}
k1 = 0;
if (nr) {
if (prevkey[0]) {
n = ch = 0;
while (data[n] == prevkey[n]) {
if (prevkey[n] == '"') ch = !ch;
if (!ch && k1 == 0 && (prevkey[n] == '(')) k1 = n + 1;
if (!ch && (prevkey[n] == ',')) k1 = n + 1;
n++;
}
while (prevkey[n]) {
if (prevkey[n] == '"') ch = !ch;
if (!ch && (prevkey[n] == ',')) {
k1 = 0;
break;
}
n++;
}
}
strcpy (prevkey, data);
if (k1 > 1) {
strcpy (&data[1], &data[k1]);
}
}
if (j < 0) {
if (kf) {
if (k1) {
printf ("%c%s", '^', data);
}
else {
printf ("%s%s", global + chop + 1, data);
}
}
if (dkf && !nr) {
printf ("=");
}
else if (kf) {
printf ("\n");
}
}
else {
fprintf (stderr, "[%d][%d] <illegal subscript>\n", length, koffs);
}
}
length = UNSIGN (block[i++]);
stcpy0 (data, &block[i], (long) length);
data[length] = EOL;
if (numeric (data)) {
data[length] = 0;
i += length;
}
else {
CtrlFlag = 0;
data[0] = '"';
k = 1;
while (length-- > 0) {
ch = UNSIGN (block[i++]);
if ((ch >= SP) && (ch < DEL)) {
if (CtrlFlag) { /* close Bracket after CTRL */
data[k++] = ')';
data[k++] = '_';
data[k++] = '"';
CtrlFlag = 0;
}
if ((data[k++] = ch) == '"') data[k++] = ch;
}
else {
if (((ch >= NUL) && (ch < SP)) || ch == DEL) {
if (CtrlFlag) {
data[k++] = ',';
}
else {
if (k > 1) {
data[k++] = '"';
data[k++] = '_';
}
else {
k = 0;
}
data[k++] = '$';
data[k++] = 'C';
data[k++] = '(';
CtrlFlag = 1;
}
if (ch == DEL) {
data[k++] = '1';
ch -= 100;
}
if (ch >= 10) {
data[k++] = ch / 10 + '0';
ch = ch % 10;
}
data[k++] = ch + '0';
}
else {
if (CtrlFlag) { /* close Bracket after CTRL */
data[k++] = ')';
data[k++] = '_';
data[k++] = '"';
CtrlFlag = 0;
}
data[k++] = '<';
if (ch > 99) {
data[k++] = '0' + (ch / 100);
ch = ch % 100;
}
if (ch > 9) {
data[k++] = '0' + (ch / 10);
ch = ch % 10;
}
data[k++] = '0' + ch;
data[k++] = '>';
}
}
}
if (CtrlFlag) {
data[k++] = ')';
}
else {
data[k++] = '"';
}
data[k] = 0;
}
if (df) printf ("%s\n", data);
}
if (i != offset) fprintf (stderr, "\nwrong offset %d vs. %d\n", offset, i);
goto again;
}
int gverify (char *gpath)
{
register int j;
printf ("\n%s:\n\n", gpath);
if ((filedes = open (gpath, 0)) == -1) {
fprintf (stderr, "Cannot open file %s\007\n\r", gpath);
return 1;
}
j = 0;
while (j < MAXLEV) {
rlink[j] = 0;
llink[j] = 0;
j++;
}
level = 0;
check (ROOT);
j = 1; /* ignore level zero: there is no rightlink pointer (freeblocks instead) */
while (j < MAXLEV) { /* check last right link pointers (all zero!) */
if (rlink[j] != 0) {
printf ("\tblock #%ld right link pointer mismatch 0 vs. %ld\012\015", llink[j], rlink[j]);
showpath ();
}
j++;
}
/* check free blocks */
freeblks = UNSIGN (block[0][FREE]) * 65536 +
UNSIGN (block[0][FREE + 1]) * 256 +
UNSIGN (block[0][FREE + 2]);
while (freeblks) {
unsigned long free;
int i;
if (freeblks > no_of_blks) {
printf ("\tblock# %ld (free list) greater than number of blocks (%ld)\012\015", freeblks, no_of_blks);
showpath ();
}
lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);
if (read (filedes, block[0], BLOCKLEN) < BLOCKLEN) {
printf ("\tblock #%ld is (partially) empty\012\015", freeblks);
showpath ();
exit (exstat);
}
j = UNSIGN (block[0][OFFS]) * 256 +
UNSIGN (block[0][OFFS + 1]); /* offset */
freeblks = UNSIGN (block[0][RLPTR]) * 65536 +
UNSIGN (block[0][RLPTR + 1]) * 256 +
UNSIGN (block[0][RLPTR + 1]);
i = 0;
while (i < j) {
free = UNSIGN (block[0][i++]) * 65536;
free += UNSIGN (block[0][i++]) * 256;
free += UNSIGN (block[0][i++]);
if (free > no_of_blks) {
printf ("\tblock #%ld (free) greater than number of blocks (%ld)\012\015", free, no_of_blks);
showpath ();
}
lseek (filedes, free * BLOCKLEN, 0);
read (filedes, block[1], BLOCKLEN);
if (block[1][BTYP] != EMPTY) {
printf ("\tblock #%ld expected block type: EMPTY\012\015", free);
if (++exstat >= ERRLIM) {
fprintf (stderr, "Error limit exceeded\012\015");
return exstat;
}
}
}
}
return exstat;
}
void check (unsigned long blknbr)
{
unsigned long left; /* current left link pointer */
unsigned long right; /* current right link pointer */
long i;
long k;
lseek (filedes, blknbr * BLOCKLEN, 0);
blck = block[level];
if (read (filedes, blck, BLOCKLEN) < BLOCKLEN) {
printf ("\tblock #%ld is (partially) empty\012\015", blknbr);
showpath ();
}
type[level] = blck[BTYP];
left = UNSIGN (blck[LLPTR]) * 65536 +
UNSIGN (blck[LLPTR + 1]) * 256 +
UNSIGN (blck[LLPTR + 2]);
right = UNSIGN (blck[RLPTR]) * 65536 +
UNSIGN (blck[RLPTR + 1]) * 256 +
UNSIGN (blck[RLPTR + 2]);
if (blknbr == ROOT) {
no_of_blks = UNSIGN (block[0][NRBLK]) * 65536 +
UNSIGN (block[0][NRBLK + 1]) * 256 +
UNSIGN (block[0][NRBLK + 2]);
}
else {
if (blknbr > no_of_blks) {
printf ("\tblock# %ld greater than number of blocks (%ld)\012\015", blknbr, no_of_blks);
showpath ();
}
}
offsets[level] = UNSIGN (blck[OFFS]) * 256 + UNSIGN (blck[OFFS + 1]);
if (rlink[level] != 0L && rlink[level] != blknbr) {
printf ("\tblock #%ld right link pointer mismatch %ld vs. %ld\012\015", llink[level], blknbr, rlink[level]);
showpath ();
}
if (llink[level] != 0L && left != llink[level]) {
printf ("\tblock #%ld left link pointer mismatch %ld vs. %ld\012\015", blknbr, left, llink[level]);
showpath ();
}
rlink[level] = right;
llink[level] = blknbr;
if (blknbr != ROOT) {
k = UNSIGN (blck[0]);
i = 0;
while (i < k) {
if (blck[i + 2] != key[i]) {
printf ("\tblock #%ld first key mismatch to pointer block(%ld)\012\015", blknbr, llink[level - 1]);
showpath ();
break;
}
i++;
}
}
switch (type[level]) {
case EMPTY:
printf ("\tblock #%ld unexpected block type: EMPTY\012\015", blknbr);
showpath ();
break;
case FBLK:
printf ("\tblock #%ld unexpected block type: FBLK\012\015", blknbr);
showpath ();
break;
case POINTER:
case BOTTOM:
/*******************************/
/* scan pointer block */
{
register long i;
register long k;
short j;
short len;
char key1[256];
key1[0] = g_EOL;
i = 0;
while (i < offsets[level]) {
j = i++; /* save adress of current entry */
if ((len = UNSIGN (blck[j]) + (k = UNSIGN (blck[i++]))) > 255) {
printf ("\tblock #%ld key too long\012\015", blknbr);
showpath ();
}
else {
if (len == 0 && j) {
printf ("\tblock #%ld empty key\012\015", blknbr);
showpath ();
}
while (k < len) key[k++] = blck[i++];
key[k] = g_EOL;
if (key_check (key)) {
printf ("\tblock #%ld illegal key\012\015", blknbr);
showpath ();
}
if (g_collate (key1, key) == 0) {
printf ("\tblock #%ld collation mismatch\012\015", blknbr);
show (key1);
show (key);
showpath ();
}
stcpy0 (key1, key, k + 1);
level++;
check ((long) (UNSIGN (blck[i]) * 65536 +
UNSIGN (blck[i + 1]) * 256 +
UNSIGN (blck[i + 2])));
blck = block[--level];
}
i += PLEN;
if (i > DATALIM) {
printf ("\tblock #%ld pointer in status bytes\012\015", blknbr);
showpath ();
}
}
if (i > offsets[level]) {
printf ("\tblock #%ld offset mismatch %ld vs. %d\012\015", blknbr, i, offsets[level]);
showpath ();
}
}
break;
case DATA:
/* scan data block */
{
register long i;
register long k;
short len;
char key0[256];
char key1[256];
if (type[level - 1] != BOTTOM) {
printf ("\tblock #%ld unexpected block type: DATA\012\015", blknbr);
showpath ();
}
key1[0] = g_EOL;
i = 0;
while (i < offsets[level]) {
len = UNSIGN (blck[i++]);
len += (k = UNSIGN (blck[i++]));
if (len > 255) {
printf ("\tblock #%ld key too long\012\015", blknbr);
showpath ();
i += len - k;
}
else {
if (len == 0 && i > 2) {
printf ("\tblock #%ld empty key\012\015", blknbr);
showpath ();
}
while (k < len) key0[k++] = blck[i++];
key0[k] = g_EOL;
if (key_check (key0)) {
printf ("\tblock #%ld illegal key\012\015", blknbr);
showpath ();
}
if (g_collate (key1, key0) == 0) {
printf ("\tblock #%ld collation mismatch\012\015", blknbr);
show (key1);
show (key0);
showpath ();
}
stcpy0 (key1, key0, k + 1);
}
k = i + 1;
len = UNSIGN (blck[i]);
i += UNSIGN (blck[i]);
i++; /* skip data */
#ifdef NEVER
while (k < i) {
if (blck[k++] & ~0177) {
printf ("\tblock #%ld illegal character in data string\012\015", blknbr);
showpath ();
break;
}
}
#endif /* NEVER */
if (i > DATALIM) {
printf ("\tblock #%ld data in status bytes\012\015", blknbr);
showpath ();
}
}
if (i > offsets[level]) {
printf ("\tblock #%ld offset mismatch %ld vs. %d\012\015", blknbr, i, offsets[level]);
showpath ();
}
}
break;
default:
printf ("\tblock #%ld illegal type %d\012\015", blknbr, type[level]);
showpath ();
}
return;
} /* end check */
void
showpath ()
{ /* display path of pointers */
int i;
if (level > 1)
for (i = 0; i < level; i++)
printf (" path level(%d)=%ld\012\015", i, llink[i]);
if (++exstat >= ERRLIM) {
fprintf (stderr, "Error limit exceeded (%hd errors)\012\015", exstat);
return;
}
return;
}
/******************************************************************************/
int key_check (char *key) /* checks a global key in compressed form */
{
short ch,
typ = 0;
while ((ch = UNSIGN (*key++)) != g_EOL) {
if (ch == (DEL << 1)) {
if ((ch = UNSIGN (*key++)) == (DEL << 1))
key++;
ch = SP;
}
if (ch >= SP) {
if (typ == 2)
return 1;
typ = 1;
}
/* alphabetics */
else {
if (typ == 1)
return 1;
typ = 2; /* numerics '.' '-' */
if (ch >= 20 && ch != POINT && ch != MINUS)
return 1; /* illegal character */
}
if (ch & 01)
typ = 0; /* comma between two indices */
}
return 0;
} /* end key_check */
/******************************************************************************/
static short int g_collate (char s[], char t[]) /* if 't' follows 's' in MUMPS collating */
{
register int chs = *s;
register int cht = *t;
register int tx = 0;
register int sx;
short dif;
/* the empty one is the leader! */
if (chs == g_EOL) {
if (cht == g_EOL)
return 2;
return 1;
}
if (cht == g_EOL)
return FALSE;
while (cht == s[tx]) {
if (cht == g_EOL)
return 0;
cht = t[++tx];
} /* (s==t) */
chs = s[tx];
if (chs == OMEGA)
return 0;
if (chs == ALPHA)
return cht != g_EOL;
if (chs == g_EOL && t[tx - 1] & 01)
return 1;
if (cht == g_EOL && s[tx - 1] & 01)
return 0;
/* vade retro usque ad comma */
if (tx > 0) {
tx--;
while ((t[tx] & 01) == 0)
if (--tx < 0)
break;
tx++;
}
chs = s[tx];
cht = t[tx];
if (UNSIGN (chs) <= POINT) { /* then come numerics */
if (UNSIGN (cht) > POINT)
return UNSIGN (cht) != g_EOL;
/* both are numeric! now compare numeric values */
/*****g_comp()*********************************************************/
if (chs == MINUS) {
if (cht != MINUS)
return 1;
} else {
if (cht == MINUS)
return 0;
}
if (chs == 1 && cht == POINT)
return 1;
if (cht == 1 && chs == POINT)
return 0;
dif = sx = tx;
while (s[sx] != POINT) {
if (s[sx++] & 01)
break;
}
while (t[tx] != POINT) {
if (t[tx++] & 01)
break;
}
if (tx > sx)
return (cht != MINUS);
if (tx < sx)
return (cht == MINUS);
tx = dif;
while ((cht >> 1) == (chs >> 1)) {
if (cht & 01)
return t[dif] == MINUS;
if (chs & 01)
return t[dif] != MINUS;
chs = s[++tx];
cht = t[tx];
}
return (((cht >> 1) > (chs >> 1)) == (t[dif] != MINUS))
&& (t[tx] != s[tx]);
/**********************************************************************/
}
if (UNSIGN (cht) <= POINT)
return 0;
while ((dif = (UNSIGN (cht) >> 1) - (UNSIGN (chs) >> 1)) == 0) { /* ASCII collating */
if ((cht & 01) && ((chs & 01) == 0))
return 0;
if ((chs & 01) && ((cht & 01) == 0))
return 1;
chs = s[++tx];
cht = t[tx];
}
if (chs == g_EOL)
return 1;
if (cht == g_EOL)
return 0;
return dif > 0;
} /* end g_collate */
/******************************************************************************/
void show (char key[])
{
int k,
ch,
i,
j;
char data[256];
k = 0;
i = 0;
j = 0;
while ((ch = UNSIGN (key[i++])) != g_EOL) {
if (k) {
k = 0;
if (ch > ' ')
data[j++] = '"';
}
data[j] = (ch > SP ? (ch >> 1) : (ch < 20 ? (ch >> 1) + '0' : (ch >> 1) + ' '));
if (data[j++] == '"')
data[j++] = '"';
if (ch & 01) {
if (ch > SP)
data[j++] = '"';
data[j++] = ',';
k = 1;
}
}
data[j--] = 0;
printf ("(%s);", data);
return;
} /* end show() */
/******************************************************************************/
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>