home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libstyle / stystruc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  15.8 KB  |  765 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* style struck used to hold style associations
  20.  *
  21.  * Designed and Implemented by Lou Montulli '97
  22.  */
  23.  
  24. #include "xp.h"
  25. #include "stystruc.h"
  26.  
  27. /* class to hold style information between style sheet parser
  28.  * and layout engine
  29.  */
  30.  
  31. #define INCREASE_ARRAY_BY 5
  32. #define INITIAL_ARRAY_SIZE 10
  33.  
  34. typedef enum {
  35.     CHAR_VALUE,
  36.     SS_NUM_VALUE
  37. } ss_pair_type;
  38.  
  39. typedef struct _ss_pair {
  40.     char         *name;
  41.     ss_pair_type  value_type;
  42.     void         *value;
  43.     int32          priority;
  44. } ss_pair;
  45.  
  46. typedef struct _SS_StyleStruct {
  47.     StyleStructInterface  *vtable;
  48.     int32                  refcount;
  49.  
  50.     /* private data */
  51.     ss_pair ** pair_array;
  52.     int32      pair_array_size;
  53.     int32      pair_array_first_unused_index;
  54.  
  55. } SS_StyleStruct;
  56.  
  57. /* 
  58.  * allocate SS_StyleStructs from a pool
  59.  */
  60. static XP_AllocStructInfo SS_StyleStructAlloc =
  61.   { XP_INITIALIZE_ALLOCSTRUCTINFO(sizeof(SS_StyleStruct)) };
  62.  
  63. void
  64. SS_freeSSNumber(SS_StyleStruct *self, SS_Number *obj)
  65. {
  66.     if(!obj)
  67.         return;
  68.  
  69.     XP_FREEIF(obj->units);
  70.     XP_FREE(obj);
  71. }
  72.  
  73. SS_Number *
  74. SS_newSSNumber(SS_StyleStruct *self, double value, char *units)
  75. {
  76.     SS_Number *new_num;
  77.  
  78.     if(!units)
  79.     {
  80.         XP_ASSERT(0);
  81.         return NULL;    
  82.     }
  83.  
  84.     /* alloc an ss_num */
  85.     new_num = XP_CALLOC(1, sizeof(SS_Number));
  86.     if(!new_num)
  87.         return NULL;
  88.  
  89.     new_num->value = value;
  90.     new_num->units = XP_STRDUP(units);
  91.  
  92.     if(!new_num->units)
  93.     {
  94.         XP_FREE(new_num);
  95.         return NULL;
  96.     }
  97.  
  98.     return(new_num);
  99. }
  100.  
  101. SS_Number *
  102. SS_copySSNumber(SS_StyleStruct *self, SS_Number *old_num)
  103. {
  104.     if(!old_num)
  105.     {
  106.         XP_ASSERT(0);
  107.         return NULL;    
  108.     }
  109.  
  110.     return(SS_newSSNumber(self, old_num->value, old_num->units));
  111. }
  112.  
  113. void
  114. ss_expand_array(SS_StyleStruct *self)
  115. {
  116.     if(self->pair_array)
  117.     {
  118.         self->pair_array_size += INCREASE_ARRAY_BY;
  119.         self->pair_array = XP_REALLOC(self->pair_array, 
  120.                                       self->pair_array_size*sizeof(ss_pair*));
  121.     }
  122.     else
  123.     {
  124.         self->pair_array_size = INITIAL_ARRAY_SIZE;
  125.         self->pair_array = XP_CALLOC(self->pair_array_size, sizeof(ss_pair*));
  126.     }
  127.  
  128.     if(!self->pair_array)
  129.       {
  130.         self->pair_array_first_unused_index = 0;
  131.         self->pair_array_size = 0;
  132.       }
  133. }
  134.  
  135. void 
  136. ss_free_ss_pair(SS_StyleStruct *self, ss_pair *pair)
  137. {
  138.     if(pair)
  139.     {
  140.         XP_FREEIF(pair->name);
  141.         switch(pair->value_type)
  142.         {
  143.             case CHAR_VALUE:
  144.                 XP_FREEIF(pair->value);
  145.                 break;
  146.  
  147.             case SS_NUM_VALUE:
  148.                 SS_freeSSNumber(self, (SS_Number*)pair->value);
  149.                 break;
  150.  
  151.             default:
  152.                 XP_ASSERT(0);
  153.         }
  154.  
  155.         XP_FREE(pair);
  156.     }
  157. }
  158.  
  159. ss_pair *
  160. ss_find_pair(SS_StyleStruct *self, char *name)
  161. {
  162.     int i;
  163.  
  164.     for(i = 0; i < self->pair_array_first_unused_index; i++)
  165.     {
  166.         if(!strcasecomp(self->pair_array[i]->name, name))
  167.             return(self->pair_array[i]);
  168.     }
  169.  
  170.     return NULL;
  171. }
  172.  
  173. int32 
  174. ss_find_pair_index(SS_StyleStruct *self, ss_pair *pair)
  175. {
  176.     int i;
  177.  
  178.     for(i = 0; i < self->pair_array_first_unused_index; i++)
  179.     {
  180.         if((self->pair_array[i] == pair))
  181.             return(i);
  182.     }
  183.  
  184.     return -1;
  185. }
  186.  
  187. /* remove the pair from the pair array and
  188.  * free's the pair if found.
  189.  */
  190. void
  191. ss_delete_pair(SS_StyleStruct *self, ss_pair *pair)
  192. {
  193.     /* find the pair index */    
  194.     int32 index = ss_find_pair_index(self, pair);
  195.  
  196.     if(index > -1)
  197.     {
  198.         ss_free_ss_pair(self, self->pair_array[index]);
  199.     
  200.         /* shift the array back over the deleted pair */
  201.         if(index < self->pair_array_first_unused_index)
  202.         {
  203.             int32 move_size = (self->pair_array_first_unused_index-index)-1;
  204.             move_size *= sizeof(ss_pair*);
  205.             if(move_size)
  206.                 XP_MEMMOVE(&self->pair_array[index], &self->pair_array[index+1], move_size);
  207.             self->pair_array_first_unused_index--;
  208.         }
  209.     }
  210.     else
  211.     {
  212.         /* cant find pair */
  213.         XP_ASSERT(0);
  214.     }
  215.  
  216. }
  217.  
  218. void
  219. ss_add_to_array(SS_StyleStruct *self, ss_pair *pair)
  220. {
  221.     if(!pair || !pair->name)
  222.     {
  223.         XP_ASSERT(0);
  224.         return;
  225.     }
  226.  
  227.     if(self->pair_array_size <= self->pair_array_first_unused_index)
  228.         ss_expand_array(self);
  229.     
  230.     if(self->pair_array)
  231.     {
  232. #if DEBUG
  233.         /* check for dups */
  234.         ss_pair *dup = ss_find_pair(self, pair->name);
  235.  
  236.         if(dup)
  237.             XP_ASSERT(0);
  238. #endif
  239.  
  240.         self->pair_array[self->pair_array_first_unused_index++] = pair;
  241.     }
  242.     else
  243.     {
  244.         ss_free_ss_pair(self, pair);
  245.     }
  246. }
  247.  
  248. void
  249. ss_free_pair_array(SS_StyleStruct *self)
  250. {
  251.     int i;
  252.  
  253.     if(self->pair_array)
  254.     {
  255.         for(i = 0; i < self->pair_array_first_unused_index; i++)
  256.         {
  257.             ss_free_ss_pair(self, self->pair_array[i]);
  258.         }
  259.  
  260.         XP_FREE(self->pair_array);
  261.     }
  262.         
  263.     self->pair_array_size = 0;
  264.     self->pair_array_first_unused_index = 0;
  265. }
  266.  
  267. void
  268. SS_setString(SS_StyleStruct *self, char *name, char *value, int32 priority)
  269. {
  270.     ss_pair *new_pair;
  271.     ss_pair *dup;
  272.  
  273.     /* check for dups */
  274.     dup = ss_find_pair(self, name);
  275.  
  276.     if(dup)
  277.     {
  278.         if(dup->priority <= priority)
  279.             ss_delete_pair(self, dup);
  280.         else
  281.             return;  /* ignore this set call */
  282.     }
  283.  
  284.     /* alloc a pair */
  285.     new_pair = XP_CALLOC(1, sizeof(ss_pair));
  286.  
  287.     if(new_pair)
  288.     {
  289.         new_pair->name = XP_STRDUP(name);
  290.         new_pair->value_type = CHAR_VALUE;
  291.         new_pair->value = XP_STRDUP(value);
  292.         new_pair->priority = priority;
  293.  
  294.         if(!new_pair->name || !new_pair->value)
  295.         {
  296.             /* malloc error */
  297.             XP_FREE(new_pair);
  298.             XP_FREEIF(new_pair->name);
  299.             XP_FREEIF(new_pair->value);
  300.             return;
  301.         }
  302.  
  303.         ss_add_to_array(self, new_pair);
  304.     }
  305. }
  306.  
  307. void
  308. SS_setNumber(SS_StyleStruct *self, char *name, SS_Number *value, int32 priority)
  309. {
  310.     SS_Number *ss_num;
  311.     ss_pair *new_pair;
  312.     ss_pair *dup;
  313.  
  314.     /* check for dups */
  315.     dup = ss_find_pair(self, name);
  316.  
  317.     if(dup)
  318.     {
  319.         if(dup->priority <= priority)
  320.             ss_delete_pair(self, dup);
  321.         else
  322.             return;  /* ignore this set call */
  323.     }
  324.  
  325.     /* alloc a pair */
  326.     new_pair = XP_CALLOC(1, sizeof(ss_pair));
  327.  
  328.     if(new_pair)
  329.     {
  330.         /* alloc an ss_num */
  331.         ss_num = SS_copySSNumber(self, value);
  332.  
  333.         new_pair->name = XP_STRDUP(name);
  334.         new_pair->value_type = SS_NUM_VALUE;
  335.         new_pair->value = ss_num;
  336.         new_pair->priority = priority;
  337.  
  338.         if(!new_pair->name || !new_pair->value)
  339.         {
  340.             /* malloc error */
  341.             XP_FREE(new_pair);
  342.             XP_FREEIF(new_pair->name);
  343.             SS_freeSSNumber(self, new_pair->value);
  344.             
  345.             return;
  346.         }
  347.  
  348.         ss_add_to_array(self, new_pair);
  349.     }
  350. }
  351.  
  352. char *
  353. SS_getString(SS_StyleStruct *self, char *name)
  354. {
  355.     ss_pair *pair = ss_find_pair(self, name);
  356.  
  357.     if(pair && pair->value)
  358.     {
  359.         if(pair->value_type == CHAR_VALUE)
  360.         {
  361.             return(XP_STRDUP((char*)pair->value));
  362.         }
  363.         else if(pair->value_type == SS_NUM_VALUE)
  364.         {
  365.             SS_Number *ss_num = (SS_Number*)pair->value;
  366.             char *rv = PR_smprintf("%f", ss_num->value);
  367.             StrAllocCat(rv, ss_num->units);
  368.  
  369.             return(rv);
  370.         }
  371.         else
  372.         {
  373.             XP_ASSERT(0);
  374.         }
  375.     }
  376.  
  377.     return(NULL);
  378. }
  379.  
  380. SS_Number *
  381. SS_stringToSSNumber(SS_StyleStruct *self, char *num_string)
  382. {
  383.     char *ptr, *num_ptr;
  384.     double num_val;
  385.  
  386.     ptr = num_string;
  387.  
  388.     /* skip any whitespace */
  389.     while(XP_IS_SPACE(*ptr)) ptr++;
  390.  
  391.     /* save a pointer to the first non white char */
  392.     num_ptr = ptr;
  393.  
  394.     /* go past any sign in front of the number */
  395.     if(*ptr == '-' || *ptr == '+') ptr++;
  396.  
  397.     /* go forward until a non number is encountered */
  398.     while(XP_IS_DIGIT(*ptr)) ptr++;
  399.  
  400.     /* go past a decimal */
  401.     if(*ptr == '.') ptr++;
  402.  
  403.     while(XP_IS_DIGIT(*ptr)) ptr++;
  404.  
  405.     /* skip any whitespace between the number and units */
  406.     while(XP_IS_SPACE(*ptr)) ptr++;
  407.  
  408.     /* 
  409.          * no need to clear out the string at the end since
  410.      * atof will do that for us, and writting to the string
  411.      * will make us crash
  412.      *
  413.      * ptr_value = *ptr;
  414.      * *ptr = '\0';
  415.       * *ptr = ptr_value;    
  416.      */
  417.     num_val = atof(num_ptr);
  418.  
  419.     return(SS_newSSNumber(self, num_val, ptr));
  420. }
  421.  
  422. SS_Number *
  423. SS_getNumber(SS_StyleStruct *self, char *name)
  424. {
  425.     ss_pair *pair = ss_find_pair(self, name);
  426.  
  427.     if(pair && pair->value)
  428.     {
  429.         if(pair->value_type == CHAR_VALUE)
  430.         {
  431.             return SS_stringToSSNumber(self, pair->value);
  432.         }
  433.         else if(pair->value_type == SS_NUM_VALUE)
  434.         {
  435.             return(SS_copySSNumber(self, (SS_Number*)pair->value));
  436.         }
  437.         else
  438.         {
  439.             XP_ASSERT(0);
  440.         }
  441.     }
  442.  
  443.     return(NULL);
  444.  
  445. }
  446.  
  447. uint32
  448. SS_count(SS_StyleStruct *self)
  449. {
  450.    return self->pair_array_first_unused_index;
  451. }
  452.  
  453. StyleStruct *
  454. SS_duplicate(SS_StyleStruct *self)
  455. {
  456.     StyleStruct *new_ss = STYLESTRUCT_Factory_Create();
  457.     int i;
  458.  
  459.     if(!new_ss)
  460.         return NULL;
  461.  
  462.     /* add all the elements of the current struct to the new one */
  463.     for(i = 0; i < self->pair_array_first_unused_index; i++)
  464.     {
  465.         ss_pair *pair = self->pair_array[i];    
  466.  
  467.         switch(pair->value_type)
  468.         {
  469.             case CHAR_VALUE:
  470.                 STYLESTRUCT_SetString(new_ss, pair->name, (char *)pair->value, pair->priority);
  471.                 break;
  472.  
  473.             case SS_NUM_VALUE:
  474.                 STYLESTRUCT_SetNumber(new_ss, pair->name, (SS_Number*)pair->value, pair->priority);
  475.                 break;
  476.             default:
  477.                 XP_ASSERT(0);
  478.         }
  479.     }
  480.  
  481.     return new_ss;
  482. }
  483.  
  484. void
  485. SS_delete(SS_StyleStruct *self)
  486. {
  487.     self->refcount--;
  488.  
  489.     if(self->refcount > 0)
  490.         return;
  491.  
  492.     ss_free_pair_array(self);
  493.  
  494. #ifdef DEBUG
  495.     /* memset the struct so that any free memory read
  496.      * errors are immediately detectable 
  497.      */
  498.     XP_MEMSET(self, 0, sizeof(SS_StyleStruct));
  499. #endif /* DEBUG */
  500.     
  501.     /*
  502.      *return SS_StyleStruct to the pool
  503.      */
  504.     XP_FreeStruct(&SS_StyleStructAlloc, self); 
  505.     self = NULL;
  506. }
  507.  
  508. /*****************************************************
  509.  * class symantics
  510.  */
  511.  
  512. /* static vtable */
  513. const StyleStructInterface StyleStruct_interface = {
  514.  
  515.     (SS_Number* (*)(StyleStruct *self, double value, char *units))
  516.         SS_newSSNumber,
  517.     (void (*)(StyleStruct * self, SS_Number *obj))
  518.         SS_freeSSNumber,
  519.     (SS_Number* (*)(StyleStruct *self, SS_Number *old_num))
  520.         SS_copySSNumber,
  521.     (SS_Number* (*)(StyleStruct *self, char *strng))
  522.         SS_stringToSSNumber,
  523.     (void (*)(StyleStruct * self, char *name, char *value, int32 priority))
  524.         SS_setString,
  525.     (void (*)(StyleStruct * self, char *name, SS_Number *value, int32 priority))
  526.         SS_setNumber,
  527.     (char* (*)(StyleStruct * self, char *name))
  528.         SS_getString,
  529.     (SS_Number* (*)(StyleStruct * self, char *name))
  530.         SS_getNumber,
  531.     (uint32 (*)(StyleStruct * self))
  532.         SS_count,
  533.     (StyleStruct * (*)(StyleStruct * self))
  534.         SS_duplicate,
  535.     (void (*)(StyleStruct * self))
  536.         SS_delete,
  537. };
  538.  
  539.  
  540. StyleStruct *
  541. STYLESTRUCT_Factory_Create(void)
  542. {
  543.     /* initializer */
  544.     /*
  545.      * allocate SS_StyleStruct from a pool
  546.      */
  547.     SS_StyleStruct *self = (SS_StyleStruct*) XP_AllocStructZero(&SS_StyleStructAlloc); 
  548.     
  549.     if(!self)
  550.         return NULL;
  551.     
  552.     self->vtable = (void*)&StyleStruct_interface;
  553.     self->refcount = 1;
  554.  
  555.     return (StyleStruct*)self;
  556. }
  557.  
  558. #ifdef SS_TEST
  559.  
  560. typedef struct {
  561.     char name[100];
  562.     char value[100];
  563.     char units[100];
  564.     ss_pair_type type;
  565. } test_struct;
  566.  
  567. test_struct test_table[] = {
  568.  
  569. {"numone", "1", "pts", SS_NUM_VALUE},
  570. {"numtwo", "2", "pts", SS_NUM_VALUE},
  571. {"numthree", "3", "pts", SS_NUM_VALUE},
  572. {"numfour", "4", "pts", SS_NUM_VALUE},
  573. {"numfive", "5", "pts", SS_NUM_VALUE},
  574. {"numsix", "6", "pts", SS_NUM_VALUE},
  575. {"numseven", "7", "pts", SS_NUM_VALUE},
  576. {"numeight", "8", "pts", SS_NUM_VALUE},
  577. {"numnine", "9", "pts", SS_NUM_VALUE},
  578. {"numten", "10", "pts", SS_NUM_VALUE},
  579. {"numeleven", "11", "pts", SS_NUM_VALUE},
  580. {"numtwelve", "12", "pts", SS_NUM_VALUE},
  581. {"numthirteen plus spaces", "13", "pts", SS_NUM_VALUE},
  582. {"numfive hundred thowsand", "500000", "pts", SS_NUM_VALUE},
  583.  
  584. {"strone", "strone", "", CHAR_VALUE},
  585. {"strtwo", "strtwo", "", CHAR_VALUE},
  586. {"strthree", "strthree", "", CHAR_VALUE},
  587. {"strfour", "strfour", "", CHAR_VALUE},
  588. {"strfive", "strfive", "", CHAR_VALUE},
  589. {"strsix", "strsix", "", CHAR_VALUE},
  590. {"strseven", "strseven", "", CHAR_VALUE},
  591.  
  592. {0, 0, SS_NUM_VALUE}
  593.  
  594. };
  595.  
  596. void
  597. test_values(StyleStruct *h)
  598. {
  599.     int i;
  600.     char *ptr;
  601.     SS_Number *ss;
  602.     char buf[200];
  603.  
  604.     for(i=0; *test_table[i].name; i++)
  605.     {
  606.         test_struct *ts = &test_table[i];
  607.  
  608.         printf("testing name: %s\n", ts->name);
  609.  
  610.         switch(ts->type)
  611.         {
  612.             case CHAR_VALUE:
  613.                 ptr = STYLESTRUCT_GetString(h, ts->name);
  614.  
  615.                 if(!ptr)
  616.                 {
  617.                     printf("Error: value not found for name: %s\n", ts->name);
  618.                 }
  619.                 else if(strcmp(ptr, ts->value))
  620.                 {
  621.                     printf("Error: value does not match, old: %s new: %s\n", ts->value, ptr);
  622.                     XP_FREE(ptr);
  623.                 }
  624.                 break;
  625.  
  626.             case SS_NUM_VALUE:
  627.                 /* get as string */
  628.                 ptr = STYLESTRUCT_GetString(h, ts->name);
  629.  
  630.                 if(!ptr)
  631.                 {
  632.                     printf("Error: value not found for name: %s\n", ts->name);
  633.                 }
  634.                 else
  635.                 {
  636.                     strcpy(buf, ts->value);
  637.                     strcat(buf, ts->units);
  638.                     if(strcmp(ptr, buf))
  639.                         printf("Error: value does not match, old: %s new: %s\n", buf, ptr);
  640.                     XP_FREE(ptr);
  641.                 }
  642.  
  643.                 /* get as number */
  644.                 ss = STYLESTRUCT_GetNumber(h, ts->name);
  645.                 if(!ss)
  646.                 {
  647.                     printf("Error: value not found for name: %s\n", ts->name);
  648.                 }
  649.                 else
  650.                 {
  651.                     if(ss->value != atof(ts->value))
  652.                         printf("Error: value does not match, old: %s new: %d\n", 
  653.                                 ts->value, ss->value);
  654.  
  655.                     
  656.                     if(strcmp(ss->units, ts->units))
  657.                         printf("Error: value does not match, old: %s new: %s\n", 
  658.                                 ts->units, ss->units);
  659.  
  660.                     STYLESTRUCT_FreeSSNumber(h, ss);
  661.                 }
  662.                 
  663.                 break;
  664.  
  665.             default:
  666.                 XP_ASSERT(0);
  667.                 break;
  668.         }
  669.     }
  670.  
  671.  
  672.     /* test for some names that dont exist */ 
  673.     ptr = STYLESTRUCT_GetString(h, "DOESN'T EXIST");
  674.     if(ptr)
  675.     {
  676.         printf("Error: returned value should not have been found");
  677.         XP_FREE(ptr);
  678.     }
  679.     ss = STYLESTRUCT_GetNumber(h, "THIS NAME DOES NOT EXIST");
  680.     if(ss)
  681.     {
  682.         printf("Error: returned value should not have been found");
  683.         STYLESTRUCT_FreeSSNumber(h, ss);
  684.     }
  685.  
  686. }
  687.  
  688. int
  689. main(int argc, char *argv[])
  690. {
  691.     int i;
  692.     StyleStruct *h;
  693.     char buf[200];
  694.     SS_Number *ss_num;
  695.     StyleStruct *new_ss;
  696.  
  697.     h = STYLESTRUCT_Factory_Create();
  698.  
  699.     if(!h)
  700.         exit(1);
  701.  
  702.     /* add everything as strings */
  703.     for(i=0; *test_table[i].name; i++)
  704.     {
  705.         test_struct *ts = &test_table[i];
  706.  
  707.         switch(ts->type)
  708.         {
  709.             case CHAR_VALUE:
  710.                 STYLESTRUCT_SetString(h, ts->name, ts->value);
  711.                 break;
  712.  
  713.             case SS_NUM_VALUE:
  714.                 strcpy(buf, ts->value);
  715.                 strcat(buf, ts->units);
  716.                 STYLESTRUCT_SetString(h, ts->name, buf);
  717.                 break;
  718.  
  719.             default:
  720.                 XP_ASSERT(0);
  721.                 break;
  722.         }
  723.     }
  724.  
  725.     test_values(h);
  726.  
  727.     /* add strings and numbers */
  728.     for(i=0; *test_table[i].name; i++)
  729.     {
  730.         test_struct *ts = &test_table[i];
  731.  
  732.         switch(ts->type)
  733.         {
  734.             case CHAR_VALUE:
  735.                 STYLESTRUCT_SetString(h, ts->name, ts->value);
  736.                 break;
  737.  
  738.             case SS_NUM_VALUE:
  739.                 ss_num = STYLESTRUCT_NewSSNumber(h, atol(ts->value), ts->units);
  740.                 STYLESTRUCT_SetNumber(h, ts->name, ss_num, 0);
  741.                 STYLESTRUCT_FreeSSNumber(h, ss_num);
  742.                 break;
  743.  
  744.             default:
  745.                 XP_ASSERT(0);
  746.                 break;
  747.         }
  748.     }
  749.  
  750.     test_values(h);
  751.  
  752.     /* dup the class */
  753.  
  754.     new_ss = STYLESTRUCT_Duplicate(h);
  755.     STYLESTRUCT_Delete(h);
  756.  
  757.     test_values(new_ss);
  758.  
  759.     STYLESTRUCT_Delete(new_ss);
  760.  
  761.     printf("all tests passed\n\n");
  762. }
  763.  
  764. #endif /* TEST_SS */
  765.