192 lines
3.7 KiB
C
192 lines
3.7 KiB
C
/* This file is part of the Project Athena Zephyr Notification System.
|
|
* It contains the main loop of the Zephyr server
|
|
*
|
|
* Created by: Lucien W. Van Elsen
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright (c) 1991 by the Massachusetts Institute of Technology.
|
|
* For copying and distribution information, see the file
|
|
* "mit-copyright.h".
|
|
*/
|
|
|
|
#include <zephyr/mit-copyright.h>
|
|
#include "zserver.h"
|
|
|
|
#ifndef lint
|
|
#ifndef SABER
|
|
static const char rcsid_zstring_c[] =
|
|
"$Id$";
|
|
#endif
|
|
#endif
|
|
|
|
static String *zhash[STRING_HASH_TABLE_SIZE];
|
|
|
|
static int
|
|
valid_utf8_p(const char* s)
|
|
{
|
|
ssize_t len;
|
|
int32_t uc;
|
|
|
|
while ((len = utf8proc_iterate((const unsigned char *)s, -1, &uc))) {
|
|
if (len <=0) return 0; /* Not valid UTF-8 encoding. */
|
|
if (!(utf8proc_codepoint_valid(uc))) return 0; /* Not valid unicode codepoint. */
|
|
if (uc == 0) return 1; /* NULL, we're done. */
|
|
s += len;
|
|
}
|
|
return 0; /* We shouldn't get here. */
|
|
}
|
|
|
|
static char *zdowncase(const char* s)
|
|
{
|
|
unsigned char *new_s_u; /* Avoid strict aliasing violation */
|
|
char *new_s, *p;
|
|
|
|
if (valid_utf8_p(s)) {
|
|
/* Use utf8proc if we're dealing with UTF-8.
|
|
* Rather than downcase, casefold and normalize to NFKC.
|
|
*/
|
|
utf8proc_map((const unsigned char *)s, 0, (unsigned char **)&new_s_u,
|
|
UTF8PROC_NULLTERM | UTF8PROC_STABLE
|
|
| UTF8PROC_CASEFOLD | UTF8PROC_COMPAT
|
|
| UTF8PROC_COMPOSE);
|
|
new_s = (char *)new_s_u;
|
|
} else {
|
|
/* If not, fall back to old methods. */
|
|
new_s = strsave(s);
|
|
p = new_s;
|
|
while(*p) {
|
|
if (isascii(*p) && isupper(*p))
|
|
*p = tolower(*p);
|
|
p++;
|
|
}
|
|
}
|
|
return new_s;
|
|
}
|
|
|
|
String *
|
|
make_string(char *s,
|
|
int downcase)
|
|
{
|
|
char *new_s;
|
|
String *new_z,*hp;
|
|
int i;
|
|
|
|
if (downcase) {
|
|
new_s = zdowncase(s);
|
|
} else {
|
|
new_s = s;
|
|
}
|
|
|
|
new_z = find_string(new_s,0);
|
|
if (new_z != NULL) {
|
|
if (downcase)
|
|
free(new_s);
|
|
new_z->ref_count++;
|
|
return(new_z);
|
|
}
|
|
|
|
/* Initialize new String */
|
|
|
|
if (!downcase)
|
|
new_s = strsave(s);
|
|
new_z = (String *) malloc(sizeof(String));
|
|
new_z->string = new_s;
|
|
new_z->ref_count = 1;
|
|
|
|
/* Add to beginning of hash table */
|
|
new_z->hash_val = hash(new_s);
|
|
i = new_z->hash_val % STRING_HASH_TABLE_SIZE;
|
|
hp = zhash[i];
|
|
new_z->next = hp;
|
|
if (hp != NULL)
|
|
hp->prev = new_z;
|
|
new_z->prev = NULL;
|
|
zhash[i] = new_z;
|
|
|
|
return new_z;
|
|
}
|
|
|
|
void
|
|
free_string(String *z)
|
|
{
|
|
if (z == (String *) NULL)
|
|
return;
|
|
|
|
z->ref_count--;
|
|
if (z->ref_count > 0)
|
|
return;
|
|
|
|
/* delete string completely */
|
|
if(z->prev == NULL)
|
|
zhash[hash(z->string) % STRING_HASH_TABLE_SIZE] = z->next;
|
|
else
|
|
z->prev->next = z->next;
|
|
|
|
if (z->next != NULL)
|
|
z->next->prev = z->prev;
|
|
|
|
free(z->string);
|
|
free(z);
|
|
}
|
|
|
|
String *
|
|
find_string(char *s,
|
|
int downcase)
|
|
{
|
|
char *new_s;
|
|
String *z;
|
|
|
|
if (downcase) {
|
|
new_s = zdowncase(s);
|
|
} else {
|
|
new_s = s;
|
|
}
|
|
|
|
z = zhash[hash(new_s) % STRING_HASH_TABLE_SIZE];
|
|
while (z != NULL) {
|
|
if (strcmp(new_s, z->string) == 0)
|
|
break;
|
|
z = z->next;
|
|
}
|
|
|
|
if (downcase)
|
|
free(new_s);
|
|
|
|
return z;
|
|
}
|
|
|
|
int
|
|
comp_string(String *a,
|
|
String *b)
|
|
{
|
|
if (a->hash_val > b->hash_val)
|
|
return 1;
|
|
if (a->hash_val < b->hash_val)
|
|
return -1;
|
|
return strcmp(a->string,b->string);
|
|
}
|
|
|
|
void
|
|
print_string_table(FILE *f)
|
|
{
|
|
String *p;
|
|
int i;
|
|
|
|
for(i = 0; i < STRING_HASH_TABLE_SIZE; i++) {
|
|
p = zhash[i];
|
|
while (p != (String *) NULL) {
|
|
fprintf(f,"[%d] %s\n",p->ref_count,p->string);
|
|
p = p->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
String *
|
|
dup_string(String *z)
|
|
{
|
|
z->ref_count++;
|
|
return z;
|
|
}
|
|
|