]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOString.m
renamed packages as discussed in the developer list
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOString.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "WOHTMLDynamicElement.h"
24 #include "WOElement+private.h"
25 #include "common.h"
26 #import <Foundation/NSNumberFormatter.h>
27 #import <Foundation/NSDateFormatter.h>
28
29 /*
30   Usage:
31     MyString: WOString {
32       value      = myCalendarDate;
33       dateformat = "%B %Y %T";
34       insertBR   = NO;
35       nilString  = "no date is set !";
36       escapeHTML = YES;
37     };
38
39   Hierarchy:
40     WOHTMLDynamicElement
41       WOString
42         _WOSimpleStaticString
43         _WOSimpleStaticASCIIString
44         _WOComplexString
45 */
46
47 @interface WOString : WOHTMLDynamicElement
48 @end /* WOString */
49
50 @interface _WOTemporaryString : NSObject
51 @end
52
53 @interface _WOSimpleStaticString : WOString
54 {
55   NSString *value;
56 }
57 @end /* WOSimpleStaticString */
58
59 @interface _WOSimpleStaticASCIIString : WOString
60 {
61   const unsigned char *value;
62 }
63 @end /* _WOSimpleStaticASCIIString */
64
65 @interface _WOSimpleDynamicString : WOString
66 {
67   WOAssociation *value;
68 }
69 @end /* WOSimpleStaticString */
70
71 @interface _WOComplexString : WOString
72 {
73   WOAssociation *value;          // object
74   WOAssociation *escapeHTML;     // BOOL
75   WOAssociation *numberformat;   // string
76   WOAssociation *dateformat;     // string
77   WOAssociation *formatter;      // WO4: NSFormatter object
78   WOAssociation *valueWhenEmpty; // WO4.5
79   
80   // non-WO attributes
81   WOAssociation *insertBR;   // insert <BR> tags for newlines
82   WOAssociation *nilString;  // string to use if value is nil - DEPRECATED!
83   WOAssociation *style;      // insert surrounding <span class="style">
84 }
85
86 @end /* WOComplexString */
87
88 @implementation WOString
89
90 + (int)version {
91   return [super version] + 1 /* v3 */;
92 }
93 + (void)initialize {
94   NSAssert2([super version] == 2,
95             @"invalid superclass (%@) version %i !",
96             NSStringFromClass([self superclass]), [super version]);
97 }
98
99 + (id)allocWithZone:(NSZone *)zone {
100   static Class WOStringClass = Nil;
101   static _WOTemporaryString *temporaryString = nil;
102   
103   if (WOStringClass == Nil)
104     WOStringClass = [WOString class];
105   if (temporaryString == nil)
106     temporaryString = [_WOTemporaryString allocWithZone:zone];
107   
108   return (self == WOStringClass)
109     ? (id)temporaryString
110     : NSAllocateObject(self, 0, zone);
111 }
112
113 @end /* WOString */
114
115 @implementation _WOSimpleDynamicString
116
117 - (id)initWithName:(NSString *)_name
118   associations:(NSDictionary *)_config
119   template:(WOElement *)_t
120 {
121   if ((self = [super initWithName:_name associations:_config template:_t])) {
122     self->value = OWGetProperty(_config, @"value");
123   }
124   return self;
125 }
126
127 - (void)dealloc {
128   [self->value release];
129   [super dealloc];
130 }
131
132 /* generating response */
133
134 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
135   [_response appendContentHTMLString:[self->value stringValueInContext:_ctx]];
136 }
137
138 /* description */
139
140 - (NSString *)associationDescription {
141   return [NSString stringWithFormat:@" value='%@'", self->value];
142 }
143
144 @end /* _WOSimpleDynamicString */
145
146 @implementation _WOSimpleStaticString
147
148 - (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
149   if ((self = [super initWithName:nil associations:nil template:nil])) {
150     // ENCODING, UNICODE
151     NSString *v;
152     unsigned length;
153
154     v = [_value stringValueInComponent:nil];
155     length = [v cStringLength];
156
157     if (length == 0) {
158       v = @"";
159     }
160     else if (_flag) {
161       char buffer[length * 6]; /* longest-encoding: '&quot;' */
162       unsigned clen = [v cStringLength];
163       char     *cbuf;
164       register char *cstr;
165       register unsigned i;
166       register char *bufPtr;
167
168 #if NeXT_Foundation_LIBRARY
169       cbuf = malloc(clen + 1);
170 #else
171       cbuf = NGMallocAtomic(clen + 1);
172 #endif
173       [v getCString:cbuf]; cbuf[clen] = '\0';
174       cstr = cbuf;
175       
176       for (i = 0, bufPtr = buffer; i < length; i++) {
177         switch (cstr[i]) {
178           case '&': /* &amp; */
179             bufPtr[0] = '&'; bufPtr[1] = 'a'; bufPtr[2] = 'm'; bufPtr[3] = 'p';
180             bufPtr[4] = ';';
181             bufPtr += 5;
182             break;
183             
184           case '<': /* &lt;   */
185             bufPtr[0] = '&'; bufPtr[1] = 'l'; bufPtr[2] = 't'; bufPtr[3] = ';';
186             bufPtr += 4;
187             break;
188             
189           case '>': /* &gt;   */
190             bufPtr[0] = '&'; bufPtr[1] = 'g'; bufPtr[2] = 't'; bufPtr[3] = ';';
191             bufPtr += 4;
192             break;
193             
194           case '"': /* &quot; */
195             bufPtr[0] = '&'; bufPtr[1] = 'q'; bufPtr[2] = 'u';
196             bufPtr[3] = 'o'; bufPtr[4] = 't'; bufPtr[5] = ';';
197             bufPtr += 6;
198             break;
199             
200           default:
201             *bufPtr = cstr[i];
202             bufPtr++;
203             break;
204         }
205       }
206 #if NeXT_Foundation_LIBRARY
207       if (cbuf) free(cbuf);
208 #else
209       if (cbuf) NGFree(cbuf);
210 #endif
211       self->value = [[NSString allocWithZone:[self zone]]
212                                initWithCString:&(buffer[0])
213                                length:(bufPtr - &(buffer[0]))];
214     }
215     else {
216       self->value = [v copyWithZone:[self zone]];
217     }
218   }
219   return self;
220 }
221
222 - (id)initWithName:(NSString *)_name
223   associations:(NSDictionary *)_config
224   template:(WOElement *)_t
225 {
226   if ((self = [super initWithName:_name associations:_config template:_t])) {
227     WOAssociation *avalue, *aescape;
228     BOOL doEscape;
229     
230     avalue  = OWGetProperty(_config, @"value");
231     aescape = OWGetProperty(_config, @"escapeHTML");
232     
233     doEscape = (aescape != nil) ? [aescape boolValueInComponent:nil] : YES;
234     self = [self initWithValue:avalue escapeHTML:doEscape];
235   }
236   return self;
237 }
238
239 - (void)dealloc {
240   [self->value release];
241   [super dealloc];
242 }
243
244 /* generating response */
245
246 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
247   WOResponse_AddString(_response, self->value);
248 }
249
250 /* description */
251
252 - (NSString *)associationDescription {
253   return [NSString stringWithFormat:@" value='%@'", self->value];
254 }
255
256 @end /* WOSimpleStaticString */
257
258 @implementation _WOSimpleStaticASCIIString
259
260 - (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
261   if ((self = [super initWithName:nil associations:nil template:nil])) {
262     // ENCODING, UNICODE
263     NSString *v;
264     unsigned length;
265     
266     v = [_value stringValueInComponent:nil];
267     length = [v cStringLength];
268     
269     if (length == 0) {
270       self->value = NULL;
271     }
272     else if (_flag) {
273       unsigned char *buffer;
274       register unsigned char *cbuf;
275       register unsigned char *bufPtr;
276       register unsigned      i;
277       unsigned clen;
278       BOOL didEscape = NO;
279       
280       clen = [v cStringLength];
281       cbuf = malloc(clen + 2);
282       [v getCString:cbuf]; cbuf[clen] = '\0';
283       
284       buffer = malloc(clen * 6 + 2); /* longest-encoding: '&quot;' */
285       
286       for (i = 0, bufPtr = buffer; i < length; i++) {
287         switch (cbuf[i]) {
288           case '&': /* &amp; */
289             bufPtr[0] = '&'; bufPtr[1] = 'a'; bufPtr[2] = 'm'; bufPtr[3] = 'p';
290             bufPtr[4] = ';';
291             bufPtr += 5;
292             didEscape = YES;
293             break;
294             
295           case '<': /* &lt;   */
296             bufPtr[0] = '&'; bufPtr[1] = 'l'; bufPtr[2] = 't'; bufPtr[3] = ';';
297             bufPtr += 4;
298             didEscape = YES;
299             break;
300             
301           case '>': /* &gt;   */
302             bufPtr[0] = '&'; bufPtr[1] = 'g'; bufPtr[2] = 't'; bufPtr[3] = ';';
303             bufPtr += 4;
304             didEscape = YES;
305             break;
306             
307           case '"': /* &quot; */
308             bufPtr[0] = '&'; bufPtr[1] = 'q'; bufPtr[2] = 'u';
309             bufPtr[3] = 'o'; bufPtr[4] = 't'; bufPtr[5] = ';';
310             bufPtr += 6;
311             didEscape = YES;
312             break;
313             
314           default:
315             if ((*bufPtr = cbuf[i]) > 127) {
316               NSLog(@"WARNING: string is not ASCII as required for "
317                     @"SimpleStaticASCIIString !!! '%@'", v);
318             }
319             bufPtr++;
320             break;
321         }
322       }
323       if (didEscape) {
324         if (cbuf) free(cbuf);
325         clen = (bufPtr - buffer);
326         self->value = malloc(clen + 2);
327         strncpy((char *)self->value, buffer, clen);
328         ((unsigned char *)self->value)[clen] = '\0';
329       }
330       else {
331         self->value = cbuf;
332       }
333       if (buffer) free(buffer);
334     }
335     else {
336       self->value = malloc(length + 2);
337       [v getCString:(char*)self->value];
338     }
339   }
340   return self;
341 }
342
343 - (id)initWithName:(NSString *)_name
344   associations:(NSDictionary *)_config
345   template:(WOElement *)_t
346 {
347   if ((self = [super initWithName:_name associations:_config template:_t])) {
348     WOAssociation *avalue, *aescape;
349     BOOL doEscape;
350     
351     avalue  = OWGetProperty(_config, @"value");
352     aescape = OWGetProperty(_config, @"escapeHTML");
353     
354     doEscape = (aescape != nil) ? [aescape boolValueInComponent:nil] : YES;
355     self = [self initWithValue:avalue escapeHTML:doEscape];
356   }
357   return self;
358 }
359
360 - (void)dealloc {
361   if (self->value) free((char *)self->value);
362   [super dealloc];
363 }
364
365 /* generating response */
366
367 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
368   if (self->value) WOResponse_AddCString(_response, self->value);
369 }
370
371 /* description */
372
373 - (NSString *)associationDescription {
374   return [NSString stringWithFormat:@" value='%s'", 
375                      self->value ? self->value : (void*)""];
376 }
377
378 @end /* WOSimpleStaticASCIIString */
379
380 @implementation _WOComplexString
381
382 static NSNumber      *yesNum = nil;
383 static WOAssociation *yesAssoc = nil;
384
385 + (void)initialize {
386   if (yesNum   == nil) yesNum = [[NSNumber numberWithBool:YES] retain];
387   if (yesAssoc == nil) 
388     yesAssoc = [[WOAssociation associationWithValue:yesNum] retain];
389 }
390
391 - (id)initWithName:(NSString *)_name
392   associations:(NSDictionary *)_config
393   template:(WOElement *)_t
394 {
395   if ((self = [super initWithName:_name associations:_config template:_t])) {
396     self->value          = OWGetProperty(_config, @"value");
397     self->escapeHTML     = OWGetProperty(_config, @"escapeHTML");
398     self->insertBR       = OWGetProperty(_config, @"insertBR");
399     self->nilString      = OWGetProperty(_config, @"nilString");
400     self->valueWhenEmpty = OWGetProperty(_config, @"valueWhenEmpty");
401     self->style          = OWGetProperty(_config, @"style");
402
403     if (self->nilString != nil && self->valueWhenEmpty != nil) {
404       [self logWithFormat:
405               @"WARNING: 'valueWhenEmpty' AND 'nilString' bindings are set, "
406               @"use only one! (nilString is deprecated!)"];
407     }
408     else if (self->nilString != nil) {
409       [self debugWithFormat:
410               @"Note: using deprecated 'nilString' binding, "
411               @"use 'valueWhenEmpty' instead."];
412     }
413     
414     self->formatter    = OWGetProperty(_config, @"formatter");
415     self->numberformat = OWGetProperty(_config, @"numberformat");
416     self->dateformat   = OWGetProperty(_config, @"dateformat");
417     
418     if (self->formatter == nil) {
419       if ([_config objectForKey:@"formatterClass"]) {
420         WOAssociation *assoc;
421         NSString      *className;
422         NSFormatter   *fmt = nil;
423         Class         clazz;
424         
425         assoc = [OWGetProperty(_config, @"formatterClass") autorelease];
426         if (![assoc isValueConstant])
427           [self logWithFormat:@"non-constant 'formatterClass' binding!"];
428         className = [assoc stringValueInComponent:nil];
429         clazz     = NSClassFromString(className);
430         
431         if ((assoc = [OWGetProperty(_config, @"format") autorelease])) {
432           NSString *format = nil;
433           
434           if (![assoc isValueConstant])
435             [self logWithFormat:@"non-constant 'format' binding!"];
436           format = [assoc stringValueInComponent:nil];
437           
438           if ([clazz instancesRespondToSelector:@selector(initWithString:)])
439             fmt = [[clazz alloc] initWithString:format];
440           else {
441             [self logWithFormat:
442                     @"cannot instantiate formatter with format: '%@'", format];
443             fmt = [[clazz alloc] init];
444           }
445         }
446         else
447           fmt = [[clazz alloc] init];
448         
449         self->formatter = [[WOAssociation associationWithValue:fmt] retain];
450         [fmt release];
451       }
452     }
453
454     if (self->escapeHTML == nil)
455       self->escapeHTML = [yesAssoc retain];
456     
457     /* check formats */
458     {
459       int num = 0;
460       if (self->formatter)    num++;
461       if (self->numberformat) num++;
462       if (self->dateformat)   num++;
463       if (num > 1)
464         NSLog(@"WARNING: more than one formats specified in element %@", self);
465     }
466   }
467   return self;
468 }
469
470 - (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
471   if ((self = [super initWithName:nil associations:nil template:nil])) {
472     self->value      = [_value retain];
473     self->escapeHTML = _flag
474       ? yesAssoc
475       : [WOAssociation associationWithValue:[NSNumber numberWithBool:NO]];
476     self->escapeHTML = [self->escapeHTML retain];
477   }
478   return self;
479 }
480
481 - (void)dealloc {
482   [self->numberformat   release];
483   [self->dateformat     release];
484   [self->formatter      release];
485   [self->nilString      release];
486   [self->valueWhenEmpty release];
487   [self->value          release];
488   [self->escapeHTML     release];
489   [self->insertBR       release];
490   [self->style          release];
491   [super dealloc];
492 }
493
494 /* response generation */
495
496 - (void)_appendStringLines:(NSString *)_s withSeparator:(NSString *)_br
497   contentSelector:(SEL)_sel
498   toResponse:(WOResponse *)_response inContext:(WOContext *)_ctx
499 {
500   NSArray *lines;
501   unsigned i, count;
502   
503   lines = [_s componentsSeparatedByString:@"\n"];
504
505   for (i = 0, count = [lines count]; i < count; i++) {
506     NSString *line;
507
508     line = [lines objectAtIndex:i];
509     if (i != 0) WOResponse_AddString(_response, _br);
510     
511     [_response performSelector:_sel withObject:line];
512   }
513 }
514
515 - (NSFormatter *)_formatterInContext:(WOContext *)_ctx {
516   if (self->numberformat) {
517     NSNumberFormatter *fmt;
518
519     fmt = [[[NSNumberFormatter alloc] init] autorelease];
520     [fmt setFormat:[self->numberformat valueInComponent:[_ctx component]]];
521     return fmt;
522   }
523
524   if (self->dateformat) {
525     NSDateFormatter *fmt;
526     NSString *s;
527     
528     s = [self->dateformat valueInComponent:[_ctx component]];
529     fmt = [[NSDateFormatter alloc] initWithDateFormat:s
530                                    allowNaturalLanguage:NO];
531     return [fmt autorelease];
532   }
533   
534   if (self->formatter)
535     return [self->formatter valueInComponent:[_ctx component]];
536   
537   return nil;
538 }
539
540 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
541   WOComponent *sComponent = [_ctx component];
542   NSFormatter *fmt;
543   id          obj    = nil;
544   SEL         addSel = NULL;
545   NSString    *styleName;
546
547   fmt = [self _formatterInContext:_ctx];
548 #if DEBUG
549   if (fmt!=nil && ![fmt respondsToSelector:@selector(stringForObjectValue:)]) {
550     [sComponent logWithFormat:
551                   @"invalid formatter determined by keypath %@: %@",
552                   self->formatter, fmt];
553   }
554 #endif
555   
556   obj    = [self->value valueInContext:_ctx];
557   addSel = [self->escapeHTML boolValueInComponent:sComponent]
558     ? @selector(appendContentHTMLString:)
559     : @selector(appendContentString:);
560
561   if (fmt) {
562     NSString *formattedObj;
563     
564     formattedObj = [fmt stringForObjectValue:obj];
565 #if 0
566     if (formattedObj == nil) {
567       NSLog(@"WARNING: formatter %@ returned nil string for object %@",
568             fmt, obj);
569     }
570 #endif
571     
572     obj = formattedObj;
573   }
574   
575   obj = [obj stringValue];
576
577   styleName = [self->style stringValueInContext:_ctx];
578
579   /* handling of empty and nil values */
580
581   if (self->valueWhenEmpty) {
582     if (obj == nil || [obj length] == 0) {
583       NSString *s;
584       
585       s = [self->valueWhenEmpty stringValueInComponent:sComponent];
586       
587       /* Note: the missing escaping is intentional for WO 4.5 compatibility */
588       if (s != nil) {
589         if (styleName) {
590           [_response appendContentString:@"<span class=\""];
591           [_response appendContentHTMLAttributeValue:styleName];
592           [_response appendContentString:@"\">"];
593         }
594         [_response appendContentString:s];
595       }
596       goto closeSpan;
597     }
598   }
599   else if (self->nilString != nil && obj == nil) {
600     NSString *s;
601
602     if (styleName) {
603       [_response appendContentString:@"<span class=\""];
604       [_response appendContentHTMLAttributeValue:styleName];
605       [_response appendContentString:@"\">"];
606     }
607     s = [self->nilString stringValueInComponent:sComponent];
608     [_response performSelector:addSel withObject:s];
609     goto closeSpan;
610   }
611   else if (obj == nil)
612     return;
613
614   /* handling of non-empty values */
615   
616   if (styleName) {
617     [_response appendContentString:@"<span class=\""];
618     [_response appendContentHTMLAttributeValue:styleName];
619     [_response appendContentString:@"\">"];
620   }
621
622   if (![self->insertBR boolValueInComponent:sComponent]) {
623     [_response performSelector:addSel withObject:obj];
624   }
625   else {
626     [self _appendStringLines:obj withSeparator:@"<br />"
627           contentSelector:addSel toResponse:_response inContext:_ctx];
628   }
629   
630 closeSpan:
631   if (styleName) {
632     [_response appendContentString:@"</span>"];
633   }
634 }
635
636 /* description */
637
638 - (NSString *)associationDescription {
639   NSMutableString *str;
640   
641   str = [NSMutableString stringWithCapacity:64];
642   
643   if (self->value)      [str appendFormat:@" value=%@",      self->value];
644   if (self->escapeHTML) [str appendFormat:@" escape=%@",     self->escapeHTML];
645   if (self->insertBR)   [str appendFormat:@" insertBR=%@",   self->insertBR];
646   if (self->formatter)  [str appendFormat:@" formatter=%@",  self->formatter];
647   if (self->dateformat) [str appendFormat:@" dateformat=%@", self->dateformat];
648   if (self->numberformat)
649     [str appendFormat:@" numberformat=%@", self->numberformat];
650
651   if (self->valueWhenEmpty) 
652     [str appendFormat:@" valueWhenEmpty=%@", self->valueWhenEmpty];
653   if (self->style) 
654       [str appendFormat:@" style=%@", self->style];
655   
656   return str;
657 }
658
659 @end /* _WOComplexString */
660
661 @implementation _WOTemporaryString
662
663 static Class ComplexStringClass     = Nil;
664 static Class SimpleStringClass      = Nil;
665 static Class SimpleASCIIStringClass = Nil;
666 static Class SimpleDynStringClass   = Nil;
667
668 #define ENSURE_CACHE \
669   if (ComplexStringClass == Nil)\
670     ComplexStringClass = [_WOComplexString class];\
671   if (SimpleStringClass == Nil)\
672     SimpleStringClass = [_WOSimpleStaticString class];\
673   if (SimpleASCIIStringClass == Nil)\
674     SimpleASCIIStringClass = [_WOSimpleStaticASCIIString class];\
675   if (SimpleDynStringClass == Nil)\
676     SimpleDynStringClass = [_WOSimpleDynamicString class];
677
678 static inline Class _classForConfig(NSDictionary *_config) {
679   Class         sClass = Nil;
680   WOAssociation *assoc, *assoc2;
681   unsigned      c;
682   
683   switch ((c = [_config count])) {
684     case 0:
685       sClass = SimpleStringClass;
686       break;
687       
688     case 1:
689       if ((assoc = [_config objectForKey:@"value"])) {
690         if ([assoc isValueConstant])
691           sClass = SimpleStringClass;
692         else
693           sClass = SimpleDynStringClass;
694         break;
695       }
696       if ((assoc = [_config objectForKey:@"escapeHTML"])) {
697         if ([assoc isValueConstant])
698           sClass = SimpleStringClass;
699         break;
700       }
701       break;
702       
703     case 2:
704       if ((assoc = [_config objectForKey:@"value"])) {
705         if ((assoc2 = [_config objectForKey:@"escapeHTML"])) {
706           if ([assoc isValueConstant] && [assoc2 isValueConstant])
707             sClass = SimpleStringClass;
708
709           break;
710         }
711       }
712       break;
713       
714     default:
715       sClass = ComplexStringClass;
716       break;
717   }
718   
719   return sClass ? sClass : ComplexStringClass;
720 }
721
722 - (id)initWithName:(NSString *)_n
723   associations:(NSDictionary *)_config
724   template:(WOElement *)_t
725 {
726   Class stringClass;
727   ENSURE_CACHE;
728
729 #if DEBUG
730   if (_t != nil) {
731     NSLog(@"WARNING: WOString '%@' has contents !", _n);
732     abort();
733   }
734 #endif
735
736   stringClass = _classForConfig(_config);
737   
738   return [[stringClass alloc]
739                        initWithName:_n associations:_config template:nil];
740 }
741 - (id)initWithName:(NSString *)_name
742   associations:(NSDictionary *)_associations
743   contentElements:(NSArray *)_contents
744 {
745   Class stringClass;
746   ENSURE_CACHE;
747
748 #if DEBUG
749   if ([_contents count] > 0) {
750     NSLog(@"WARNING: WOString has contents !");
751     abort();
752   }
753 #endif
754   
755   stringClass = _classForConfig(_associations);
756   
757   return [[stringClass alloc]
758                        initWithName:_name
759                        associations:_associations
760                        contentElements:nil];
761 }
762
763 - (id)initWithValue:(WOAssociation *)_value escapeHTML:(BOOL)_flag {
764   Class stringClass;
765   ENSURE_CACHE;
766   
767   if ((_value == nil) || [_value isValueConstant])
768     stringClass = SimpleStringClass;
769   else
770     stringClass = ComplexStringClass;
771     
772   return [[stringClass alloc] initWithValue:_value escapeHTML:_flag];
773 }
774
775 - (void)dealloc {
776   NSLog(@"ERROR: called dealloc on %@", self);
777 #if DEBUG
778   abort();
779 #endif
780   return;
781 }
782
783 @end /* _WOTemporaryString */