mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 21:55:31 +00:00
769 lines
15 KiB
C
769 lines
15 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (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.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
/* style struck used to hold style associations
|
|
*
|
|
* Designed and Implemented by Lou Montulli '97
|
|
*/
|
|
|
|
#include "xp.h"
|
|
#include "stystruc.h"
|
|
|
|
/* class to hold style information between style sheet parser
|
|
* and layout engine
|
|
*/
|
|
|
|
#define INCREASE_ARRAY_BY 5
|
|
#define INITIAL_ARRAY_SIZE 10
|
|
|
|
typedef enum {
|
|
CHAR_VALUE,
|
|
SS_NUM_VALUE
|
|
} ss_pair_type;
|
|
|
|
typedef struct _ss_pair {
|
|
char *name;
|
|
ss_pair_type value_type;
|
|
void *value;
|
|
int32 priority;
|
|
} ss_pair;
|
|
|
|
typedef struct _SS_StyleStruct {
|
|
StyleStructInterface *vtable;
|
|
int32 refcount;
|
|
|
|
/* private data */
|
|
ss_pair ** pair_array;
|
|
int32 pair_array_size;
|
|
int32 pair_array_first_unused_index;
|
|
|
|
} SS_StyleStruct;
|
|
|
|
/*
|
|
* allocate SS_StyleStructs from a pool
|
|
*/
|
|
static XP_AllocStructInfo SS_StyleStructAlloc =
|
|
{ XP_INITIALIZE_ALLOCSTRUCTINFO(sizeof(SS_StyleStruct)) };
|
|
|
|
void
|
|
SS_freeSSNumber(SS_StyleStruct *self, SS_Number *obj)
|
|
{
|
|
if(!obj)
|
|
return;
|
|
|
|
XP_FREEIF(obj->units);
|
|
XP_FREE(obj);
|
|
}
|
|
|
|
SS_Number *
|
|
SS_newSSNumber(SS_StyleStruct *self, double value, char *units)
|
|
{
|
|
SS_Number *new_num;
|
|
|
|
if(!units)
|
|
{
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
/* alloc an ss_num */
|
|
new_num = XP_CALLOC(1, sizeof(SS_Number));
|
|
if(!new_num)
|
|
return NULL;
|
|
|
|
new_num->value = value;
|
|
new_num->units = XP_STRDUP(units);
|
|
|
|
if(!new_num->units)
|
|
{
|
|
XP_FREE(new_num);
|
|
return NULL;
|
|
}
|
|
|
|
return(new_num);
|
|
}
|
|
|
|
SS_Number *
|
|
SS_copySSNumber(SS_StyleStruct *self, SS_Number *old_num)
|
|
{
|
|
if(!old_num)
|
|
{
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
return(SS_newSSNumber(self, old_num->value, old_num->units));
|
|
}
|
|
|
|
void
|
|
ss_expand_array(SS_StyleStruct *self)
|
|
{
|
|
if(self->pair_array)
|
|
{
|
|
self->pair_array_size += INCREASE_ARRAY_BY;
|
|
self->pair_array = XP_REALLOC(self->pair_array,
|
|
self->pair_array_size*sizeof(ss_pair*));
|
|
}
|
|
else
|
|
{
|
|
self->pair_array_size = INITIAL_ARRAY_SIZE;
|
|
self->pair_array = XP_CALLOC(self->pair_array_size, sizeof(ss_pair*));
|
|
}
|
|
|
|
if(!self->pair_array)
|
|
{
|
|
self->pair_array_first_unused_index = 0;
|
|
self->pair_array_size = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
ss_free_ss_pair(SS_StyleStruct *self, ss_pair *pair)
|
|
{
|
|
if(pair)
|
|
{
|
|
XP_FREEIF(pair->name);
|
|
switch(pair->value_type)
|
|
{
|
|
case CHAR_VALUE:
|
|
XP_FREEIF(pair->value);
|
|
break;
|
|
|
|
case SS_NUM_VALUE:
|
|
SS_freeSSNumber(self, (SS_Number*)pair->value);
|
|
break;
|
|
|
|
default:
|
|
XP_ASSERT(0);
|
|
}
|
|
|
|
XP_FREE(pair);
|
|
}
|
|
}
|
|
|
|
ss_pair *
|
|
ss_find_pair(SS_StyleStruct *self, char *name)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < self->pair_array_first_unused_index; i++)
|
|
{
|
|
if(!strcasecomp(self->pair_array[i]->name, name))
|
|
return(self->pair_array[i]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int32
|
|
ss_find_pair_index(SS_StyleStruct *self, ss_pair *pair)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < self->pair_array_first_unused_index; i++)
|
|
{
|
|
if((self->pair_array[i] == pair))
|
|
return(i);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* remove the pair from the pair array and
|
|
* free's the pair if found.
|
|
*/
|
|
void
|
|
ss_delete_pair(SS_StyleStruct *self, ss_pair *pair)
|
|
{
|
|
/* find the pair index */
|
|
int32 index = ss_find_pair_index(self, pair);
|
|
|
|
if(index > -1)
|
|
{
|
|
ss_free_ss_pair(self, self->pair_array[index]);
|
|
|
|
/* shift the array back over the deleted pair */
|
|
if(index < self->pair_array_first_unused_index)
|
|
{
|
|
int32 move_size = (self->pair_array_first_unused_index-index)-1;
|
|
move_size *= sizeof(ss_pair*);
|
|
if(move_size)
|
|
XP_MEMMOVE(&self->pair_array[index], &self->pair_array[index+1], move_size);
|
|
self->pair_array_first_unused_index--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* cant find pair */
|
|
XP_ASSERT(0);
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
ss_add_to_array(SS_StyleStruct *self, ss_pair *pair)
|
|
{
|
|
if(!pair || !pair->name)
|
|
{
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
if(self->pair_array_size <= self->pair_array_first_unused_index)
|
|
ss_expand_array(self);
|
|
|
|
if(self->pair_array)
|
|
{
|
|
#if DEBUG
|
|
/* check for dups */
|
|
ss_pair *dup = ss_find_pair(self, pair->name);
|
|
|
|
if(dup)
|
|
XP_ASSERT(0);
|
|
#endif
|
|
|
|
self->pair_array[self->pair_array_first_unused_index++] = pair;
|
|
}
|
|
else
|
|
{
|
|
ss_free_ss_pair(self, pair);
|
|
}
|
|
}
|
|
|
|
void
|
|
ss_free_pair_array(SS_StyleStruct *self)
|
|
{
|
|
int i;
|
|
|
|
if(self->pair_array)
|
|
{
|
|
for(i = 0; i < self->pair_array_first_unused_index; i++)
|
|
{
|
|
ss_free_ss_pair(self, self->pair_array[i]);
|
|
}
|
|
|
|
XP_FREE(self->pair_array);
|
|
}
|
|
|
|
self->pair_array_size = 0;
|
|
self->pair_array_first_unused_index = 0;
|
|
}
|
|
|
|
void
|
|
SS_setString(SS_StyleStruct *self, char *name, char *value, int32 priority)
|
|
{
|
|
ss_pair *new_pair;
|
|
ss_pair *dup;
|
|
|
|
/* check for dups */
|
|
dup = ss_find_pair(self, name);
|
|
|
|
if(dup)
|
|
{
|
|
if(dup->priority <= priority)
|
|
ss_delete_pair(self, dup);
|
|
else
|
|
return; /* ignore this set call */
|
|
}
|
|
|
|
/* alloc a pair */
|
|
new_pair = XP_CALLOC(1, sizeof(ss_pair));
|
|
|
|
if(new_pair)
|
|
{
|
|
new_pair->name = XP_STRDUP(name);
|
|
new_pair->value_type = CHAR_VALUE;
|
|
new_pair->value = XP_STRDUP(value);
|
|
new_pair->priority = priority;
|
|
|
|
if(!new_pair->name || !new_pair->value)
|
|
{
|
|
/* malloc error */
|
|
XP_FREE(new_pair);
|
|
XP_FREEIF(new_pair->name);
|
|
XP_FREEIF(new_pair->value);
|
|
return;
|
|
}
|
|
|
|
ss_add_to_array(self, new_pair);
|
|
}
|
|
}
|
|
|
|
void
|
|
SS_setNumber(SS_StyleStruct *self, char *name, SS_Number *value, int32 priority)
|
|
{
|
|
SS_Number *ss_num;
|
|
ss_pair *new_pair;
|
|
ss_pair *dup;
|
|
|
|
/* check for dups */
|
|
dup = ss_find_pair(self, name);
|
|
|
|
if(dup)
|
|
{
|
|
if(dup->priority <= priority)
|
|
ss_delete_pair(self, dup);
|
|
else
|
|
return; /* ignore this set call */
|
|
}
|
|
|
|
/* alloc a pair */
|
|
new_pair = XP_CALLOC(1, sizeof(ss_pair));
|
|
|
|
if(new_pair)
|
|
{
|
|
/* alloc an ss_num */
|
|
ss_num = SS_copySSNumber(self, value);
|
|
|
|
new_pair->name = XP_STRDUP(name);
|
|
new_pair->value_type = SS_NUM_VALUE;
|
|
new_pair->value = ss_num;
|
|
new_pair->priority = priority;
|
|
|
|
if(!new_pair->name || !new_pair->value)
|
|
{
|
|
/* malloc error */
|
|
XP_FREE(new_pair);
|
|
XP_FREEIF(new_pair->name);
|
|
SS_freeSSNumber(self, new_pair->value);
|
|
|
|
return;
|
|
}
|
|
|
|
ss_add_to_array(self, new_pair);
|
|
}
|
|
}
|
|
|
|
char *
|
|
SS_getString(SS_StyleStruct *self, char *name)
|
|
{
|
|
ss_pair *pair = ss_find_pair(self, name);
|
|
|
|
if(pair && pair->value)
|
|
{
|
|
if(pair->value_type == CHAR_VALUE)
|
|
{
|
|
return(XP_STRDUP((char*)pair->value));
|
|
}
|
|
else if(pair->value_type == SS_NUM_VALUE)
|
|
{
|
|
SS_Number *ss_num = (SS_Number*)pair->value;
|
|
char *rv = PR_smprintf("%f", ss_num->value);
|
|
StrAllocCat(rv, ss_num->units);
|
|
|
|
return(rv);
|
|
}
|
|
else
|
|
{
|
|
XP_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
SS_Number *
|
|
SS_stringToSSNumber(SS_StyleStruct *self, char *num_string)
|
|
{
|
|
char *ptr, *num_ptr;
|
|
double num_val;
|
|
|
|
ptr = num_string;
|
|
|
|
/* skip any whitespace */
|
|
while(XP_IS_SPACE(*ptr)) ptr++;
|
|
|
|
/* save a pointer to the first non white char */
|
|
num_ptr = ptr;
|
|
|
|
/* go past any sign in front of the number */
|
|
if(*ptr == '-' || *ptr == '+') ptr++;
|
|
|
|
/* go forward until a non number is encountered */
|
|
while(XP_IS_DIGIT(*ptr)) ptr++;
|
|
|
|
/* go past a decimal */
|
|
if(*ptr == '.') ptr++;
|
|
|
|
while(XP_IS_DIGIT(*ptr)) ptr++;
|
|
|
|
/* skip any whitespace between the number and units */
|
|
while(XP_IS_SPACE(*ptr)) ptr++;
|
|
|
|
/*
|
|
* no need to clear out the string at the end since
|
|
* atof will do that for us, and writting to the string
|
|
* will make us crash
|
|
*
|
|
* ptr_value = *ptr;
|
|
* *ptr = '\0';
|
|
* *ptr = ptr_value;
|
|
*/
|
|
num_val = atof(num_ptr);
|
|
|
|
return(SS_newSSNumber(self, num_val, ptr));
|
|
}
|
|
|
|
SS_Number *
|
|
SS_getNumber(SS_StyleStruct *self, char *name)
|
|
{
|
|
ss_pair *pair = ss_find_pair(self, name);
|
|
|
|
if(pair && pair->value)
|
|
{
|
|
if(pair->value_type == CHAR_VALUE)
|
|
{
|
|
return SS_stringToSSNumber(self, pair->value);
|
|
}
|
|
else if(pair->value_type == SS_NUM_VALUE)
|
|
{
|
|
return(SS_copySSNumber(self, (SS_Number*)pair->value));
|
|
}
|
|
else
|
|
{
|
|
XP_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
uint32
|
|
SS_count(SS_StyleStruct *self)
|
|
{
|
|
return self->pair_array_first_unused_index;
|
|
}
|
|
|
|
StyleStruct *
|
|
SS_duplicate(SS_StyleStruct *self)
|
|
{
|
|
StyleStruct *new_ss = STYLESTRUCT_Factory_Create();
|
|
int i;
|
|
|
|
if(!new_ss)
|
|
return NULL;
|
|
|
|
/* add all the elements of the current struct to the new one */
|
|
for(i = 0; i < self->pair_array_first_unused_index; i++)
|
|
{
|
|
ss_pair *pair = self->pair_array[i];
|
|
|
|
switch(pair->value_type)
|
|
{
|
|
case CHAR_VALUE:
|
|
STYLESTRUCT_SetString(new_ss, pair->name, (char *)pair->value, pair->priority);
|
|
break;
|
|
|
|
case SS_NUM_VALUE:
|
|
STYLESTRUCT_SetNumber(new_ss, pair->name, (SS_Number*)pair->value, pair->priority);
|
|
break;
|
|
default:
|
|
XP_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
return new_ss;
|
|
}
|
|
|
|
void
|
|
SS_delete(SS_StyleStruct *self)
|
|
{
|
|
self->refcount--;
|
|
|
|
if(self->refcount > 0)
|
|
return;
|
|
|
|
ss_free_pair_array(self);
|
|
|
|
#ifdef DEBUG
|
|
/* memset the struct so that any free memory read
|
|
* errors are immediately detectable
|
|
*/
|
|
XP_MEMSET(self, 0, sizeof(SS_StyleStruct));
|
|
#endif /* DEBUG */
|
|
|
|
/*
|
|
*return SS_StyleStruct to the pool
|
|
*/
|
|
XP_FreeStruct(&SS_StyleStructAlloc, self);
|
|
self = NULL;
|
|
}
|
|
|
|
/*****************************************************
|
|
* class symantics
|
|
*/
|
|
|
|
/* static vtable */
|
|
const StyleStructInterface StyleStruct_interface = {
|
|
|
|
(SS_Number* (*)(StyleStruct *self, double value, char *units))
|
|
SS_newSSNumber,
|
|
(void (*)(StyleStruct * self, SS_Number *obj))
|
|
SS_freeSSNumber,
|
|
(SS_Number* (*)(StyleStruct *self, SS_Number *old_num))
|
|
SS_copySSNumber,
|
|
(SS_Number* (*)(StyleStruct *self, char *strng))
|
|
SS_stringToSSNumber,
|
|
(void (*)(StyleStruct * self, char *name, char *value, int32 priority))
|
|
SS_setString,
|
|
(void (*)(StyleStruct * self, char *name, SS_Number *value, int32 priority))
|
|
SS_setNumber,
|
|
(char* (*)(StyleStruct * self, char *name))
|
|
SS_getString,
|
|
(SS_Number* (*)(StyleStruct * self, char *name))
|
|
SS_getNumber,
|
|
(uint32 (*)(StyleStruct * self))
|
|
SS_count,
|
|
(StyleStruct * (*)(StyleStruct * self))
|
|
SS_duplicate,
|
|
(void (*)(StyleStruct * self))
|
|
SS_delete,
|
|
};
|
|
|
|
|
|
StyleStruct *
|
|
STYLESTRUCT_Factory_Create(void)
|
|
{
|
|
/* initializer */
|
|
/*
|
|
* allocate SS_StyleStruct from a pool
|
|
*/
|
|
SS_StyleStruct *self = (SS_StyleStruct*) XP_AllocStructZero(&SS_StyleStructAlloc);
|
|
|
|
if(!self)
|
|
return NULL;
|
|
|
|
self->vtable = (void*)&StyleStruct_interface;
|
|
self->refcount = 1;
|
|
|
|
return (StyleStruct*)self;
|
|
}
|
|
|
|
#ifdef SS_TEST
|
|
|
|
typedef struct {
|
|
char name[100];
|
|
char value[100];
|
|
char units[100];
|
|
ss_pair_type type;
|
|
} test_struct;
|
|
|
|
test_struct test_table[] = {
|
|
|
|
{"numone", "1", "pts", SS_NUM_VALUE},
|
|
{"numtwo", "2", "pts", SS_NUM_VALUE},
|
|
{"numthree", "3", "pts", SS_NUM_VALUE},
|
|
{"numfour", "4", "pts", SS_NUM_VALUE},
|
|
{"numfive", "5", "pts", SS_NUM_VALUE},
|
|
{"numsix", "6", "pts", SS_NUM_VALUE},
|
|
{"numseven", "7", "pts", SS_NUM_VALUE},
|
|
{"numeight", "8", "pts", SS_NUM_VALUE},
|
|
{"numnine", "9", "pts", SS_NUM_VALUE},
|
|
{"numten", "10", "pts", SS_NUM_VALUE},
|
|
{"numeleven", "11", "pts", SS_NUM_VALUE},
|
|
{"numtwelve", "12", "pts", SS_NUM_VALUE},
|
|
{"numthirteen plus spaces", "13", "pts", SS_NUM_VALUE},
|
|
{"numfive hundred thowsand", "500000", "pts", SS_NUM_VALUE},
|
|
|
|
{"strone", "strone", "", CHAR_VALUE},
|
|
{"strtwo", "strtwo", "", CHAR_VALUE},
|
|
{"strthree", "strthree", "", CHAR_VALUE},
|
|
{"strfour", "strfour", "", CHAR_VALUE},
|
|
{"strfive", "strfive", "", CHAR_VALUE},
|
|
{"strsix", "strsix", "", CHAR_VALUE},
|
|
{"strseven", "strseven", "", CHAR_VALUE},
|
|
|
|
{0, 0, SS_NUM_VALUE}
|
|
|
|
};
|
|
|
|
void
|
|
test_values(StyleStruct *h)
|
|
{
|
|
int i;
|
|
char *ptr;
|
|
SS_Number *ss;
|
|
char buf[200];
|
|
|
|
for(i=0; *test_table[i].name; i++)
|
|
{
|
|
test_struct *ts = &test_table[i];
|
|
|
|
printf("testing name: %s\n", ts->name);
|
|
|
|
switch(ts->type)
|
|
{
|
|
case CHAR_VALUE:
|
|
ptr = STYLESTRUCT_GetString(h, ts->name);
|
|
|
|
if(!ptr)
|
|
{
|
|
printf("Error: value not found for name: %s\n", ts->name);
|
|
}
|
|
else if(strcmp(ptr, ts->value))
|
|
{
|
|
printf("Error: value does not match, old: %s new: %s\n", ts->value, ptr);
|
|
XP_FREE(ptr);
|
|
}
|
|
break;
|
|
|
|
case SS_NUM_VALUE:
|
|
/* get as string */
|
|
ptr = STYLESTRUCT_GetString(h, ts->name);
|
|
|
|
if(!ptr)
|
|
{
|
|
printf("Error: value not found for name: %s\n", ts->name);
|
|
}
|
|
else
|
|
{
|
|
strcpy(buf, ts->value);
|
|
strcat(buf, ts->units);
|
|
if(strcmp(ptr, buf))
|
|
printf("Error: value does not match, old: %s new: %s\n", buf, ptr);
|
|
XP_FREE(ptr);
|
|
}
|
|
|
|
/* get as number */
|
|
ss = STYLESTRUCT_GetNumber(h, ts->name);
|
|
if(!ss)
|
|
{
|
|
printf("Error: value not found for name: %s\n", ts->name);
|
|
}
|
|
else
|
|
{
|
|
if(ss->value != atof(ts->value))
|
|
printf("Error: value does not match, old: %s new: %d\n",
|
|
ts->value, ss->value);
|
|
|
|
|
|
if(strcmp(ss->units, ts->units))
|
|
printf("Error: value does not match, old: %s new: %s\n",
|
|
ts->units, ss->units);
|
|
|
|
STYLESTRUCT_FreeSSNumber(h, ss);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
XP_ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* test for some names that dont exist */
|
|
ptr = STYLESTRUCT_GetString(h, "DOESN'T EXIST");
|
|
if(ptr)
|
|
{
|
|
printf("Error: returned value should not have been found");
|
|
XP_FREE(ptr);
|
|
}
|
|
ss = STYLESTRUCT_GetNumber(h, "THIS NAME DOES NOT EXIST");
|
|
if(ss)
|
|
{
|
|
printf("Error: returned value should not have been found");
|
|
STYLESTRUCT_FreeSSNumber(h, ss);
|
|
}
|
|
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i;
|
|
StyleStruct *h;
|
|
char buf[200];
|
|
SS_Number *ss_num;
|
|
StyleStruct *new_ss;
|
|
|
|
h = STYLESTRUCT_Factory_Create();
|
|
|
|
if(!h)
|
|
exit(1);
|
|
|
|
/* add everything as strings */
|
|
for(i=0; *test_table[i].name; i++)
|
|
{
|
|
test_struct *ts = &test_table[i];
|
|
|
|
switch(ts->type)
|
|
{
|
|
case CHAR_VALUE:
|
|
STYLESTRUCT_SetString(h, ts->name, ts->value);
|
|
break;
|
|
|
|
case SS_NUM_VALUE:
|
|
strcpy(buf, ts->value);
|
|
strcat(buf, ts->units);
|
|
STYLESTRUCT_SetString(h, ts->name, buf);
|
|
break;
|
|
|
|
default:
|
|
XP_ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
test_values(h);
|
|
|
|
/* add strings and numbers */
|
|
for(i=0; *test_table[i].name; i++)
|
|
{
|
|
test_struct *ts = &test_table[i];
|
|
|
|
switch(ts->type)
|
|
{
|
|
case CHAR_VALUE:
|
|
STYLESTRUCT_SetString(h, ts->name, ts->value);
|
|
break;
|
|
|
|
case SS_NUM_VALUE:
|
|
ss_num = STYLESTRUCT_NewSSNumber(h, atol(ts->value), ts->units);
|
|
STYLESTRUCT_SetNumber(h, ts->name, ss_num, 0);
|
|
STYLESTRUCT_FreeSSNumber(h, ss_num);
|
|
break;
|
|
|
|
default:
|
|
XP_ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
test_values(h);
|
|
|
|
/* dup the class */
|
|
|
|
new_ss = STYLESTRUCT_Duplicate(h);
|
|
STYLESTRUCT_Delete(h);
|
|
|
|
test_values(new_ss);
|
|
|
|
STYLESTRUCT_Delete(new_ss);
|
|
|
|
printf("all tests passed\n\n");
|
|
}
|
|
|
|
#endif /* TEST_SS */
|