blob: 04df9375ac1f7f9cee160bb232cce9278ba31228 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <string.h>
#ifndef true
#define true 1
#define false 0
#endif
#define CFC_NEED_BASE_STRUCT_DEF
#include "CFCBase.h"
#include "CFCParcel.h"
#include "CFCUtil.h"
struct CFCParcel {
CFCBase base;
char *name;
char *cnick;
char *prefix;
char *Prefix;
char *PREFIX;
};
#define MAX_PARCELS 100
static CFCParcel *registry[MAX_PARCELS + 1];
static int first_time = true;
CFCParcel*
CFCParcel_singleton(const char *name, const char *cnick) {
// Set up registry.
if (first_time) {
size_t i;
for (i = 1; i < MAX_PARCELS; i++) { registry[i] = NULL; }
first_time = false;
}
// Return the default parcel for either a blank name or a NULL name.
if (!name || !strlen(name)) {
return CFCParcel_default_parcel();
}
// Return an existing singleton if the parcel has already been registered.
size_t i;
for (i = 1; registry[i] != NULL; i++) {
CFCParcel *existing = registry[i];
if (strcmp(existing->name, name) == 0) {
if (cnick && strcmp(existing->cnick, cnick) != 0) {
CFCUtil_die("cnick '%s' for parcel '%s' conflicts with '%s'",
cnick, name, existing->cnick);
}
return existing;
}
}
if (i == MAX_PARCELS) {
CFCUtil_die("Exceeded maximum number of parcels (%d)", MAX_PARCELS);
}
// Register new parcel.
CFCParcel *singleton = CFCParcel_new(name, cnick);
registry[i] = singleton;
return singleton;
}
void
CFCParcel_reap_singletons(void) {
if (registry[0]) {
// default parcel.
CFCBase_decref((CFCBase*)registry[0]);
}
int i;
for (i = 1; registry[i] != NULL; i++) {
CFCParcel *parcel = registry[i];
CFCBase_decref((CFCBase*)parcel);
}
}
static int
S_validate_name_or_cnick(const char *orig) {
const char *ptr = orig;
for (; *ptr != 0; ptr++) {
if (!isalpha(*ptr)) { return false; }
}
return true;
}
const static CFCMeta CFCPARCEL_META = {
"Clownfish::CFC::Parcel",
sizeof(CFCParcel),
(CFCBase_destroy_t)CFCParcel_destroy
};
CFCParcel*
CFCParcel_new(const char *name, const char *cnick) {
CFCParcel *self = (CFCParcel*)CFCBase_allocate(&CFCPARCEL_META);
return CFCParcel_init(self, name, cnick);
}
CFCParcel*
CFCParcel_init(CFCParcel *self, const char *name, const char *cnick) {
// Validate name.
if (!name || !S_validate_name_or_cnick(name)) {
CFCUtil_die("Invalid name: '%s'", name ? name : "[NULL]");
}
self->name = CFCUtil_strdup(name);
// Validate or derive cnick.
if (cnick) {
if (!S_validate_name_or_cnick(cnick)) {
CFCUtil_die("Invalid cnick: '%s'", cnick);
}
self->cnick = CFCUtil_strdup(cnick);
}
else {
// Default cnick to name.
self->cnick = CFCUtil_strdup(name);
}
// Derive prefix, Prefix, PREFIX.
size_t cnick_len = strlen(self->cnick);
size_t prefix_len = cnick_len ? cnick_len + 1 : 0;
size_t amount = prefix_len + 1;
self->prefix = (char*)MALLOCATE(amount);
self->Prefix = (char*)MALLOCATE(amount);
self->PREFIX = (char*)MALLOCATE(amount);
memcpy(self->Prefix, self->cnick, cnick_len);
if (cnick_len) {
self->Prefix[cnick_len] = '_';
self->Prefix[cnick_len + 1] = '\0';
}
else {
self->Prefix[cnick_len] = '\0';
}
size_t i;
for (i = 0; i < amount; i++) {
self->prefix[i] = tolower(self->Prefix[i]);
self->PREFIX[i] = toupper(self->Prefix[i]);
}
self->prefix[prefix_len] = '\0';
self->Prefix[prefix_len] = '\0';
self->PREFIX[prefix_len] = '\0';
return self;
}
void
CFCParcel_destroy(CFCParcel *self) {
FREEMEM(self->name);
FREEMEM(self->cnick);
FREEMEM(self->prefix);
FREEMEM(self->Prefix);
FREEMEM(self->PREFIX);
CFCBase_destroy((CFCBase*)self);
}
static CFCParcel *default_parcel = NULL;
CFCParcel*
CFCParcel_default_parcel(void) {
if (default_parcel == NULL) {
default_parcel = CFCParcel_new("DEFAULT", "");
registry[0] = default_parcel;
}
return default_parcel;
}
CFCParcel*
CFCParcel_clownfish_parcel(void) {
return CFCParcel_singleton("Lucy", "Lucy");
}
int
CFCParcel_equals(CFCParcel *self, CFCParcel *other) {
if (strcmp(self->name, other->name)) { return false; }
if (strcmp(self->cnick, other->cnick)) { return false; }
return true;
}
const char*
CFCParcel_get_name(CFCParcel *self) {
return self->name;
}
const char*
CFCParcel_get_cnick(CFCParcel *self) {
return self->cnick;
}
const char*
CFCParcel_get_prefix(CFCParcel *self) {
return self->prefix;
}
const char*
CFCParcel_get_Prefix(CFCParcel *self) {
return self->Prefix;
}
const char*
CFCParcel_get_PREFIX(CFCParcel *self) {
return self->PREFIX;
}