1 /*******************************************************************
2  *
3  *    DESCRIPTION: 	string.cpp
4  *
5  *    AUTHOR: David Malcolm
6  *
7  *    HISTORY:  Created ages ago
8  *
9  *******************************************************************/
10 
11 /* Includes ********************************************************/
12 
13 #include "3dc.h"
14 #include "scstring.hpp"
15 
16 #include "strutil.h"
17 #include "indexfnt.hpp"
18 
19 	#if TrackReferenceCounted
20 	#include "dcontext.hpp"
21 	#endif
22 
23 	#define UseLocalAssert Yes
24 	#include "ourasert.h"
25 
26 /* Version settings ************************************************/
27 	#define LogStringTables	No
28 
29 /* Constants *******************************************************/
30 	#define MAX_BYTES_IN_NUMERIC_STRING	(100)
31 
32 /* Macros **********************************************************/
33 
34 /* Imported function prototypes ************************************/
35 
36 /* Imported data ***************************************************/
37 
38 #include "teletype.hpp"
39 
40 /* Exported globals ************************************************/
41 	/*static*/ SCString* SCString :: pFirst = NULL;
42 
43 /* Internal type definitions ***************************************/
44 
45 /* Internal function prototypes ************************************/
46 
47 /* Internal globals ************************************************/
48 
49 /* Exported function definitions ***********************************/
50 // class SCString
51 // public:
52 #if TrackReferenceCounted
DumpIDForReferenceDump(R_DumpContext & theContext) const53 void SCString :: DumpIDForReferenceDump(R_DumpContext& theContext) const
54 {
55 	theContext . dprintf("SCString \"%s\" refs remainining=%i\n",pProjCh_Val,CheckRef());
56 }
57 #endif
58 
pProjCh(void) const59 ProjChar* SCString :: pProjCh(void) const
60 {
61 	/* PRECONDITION */
62 	{
63 		GLOBALASSERT( pProjCh_Val );
64 	}
65 
66 	/* CODE */
67 	{
68 		return pProjCh_Val;
69 	}
70 }
71 
72 
SCString(const ProjChar * pProjCh_Init)73 SCString :: SCString
74 (
75 	const ProjChar* pProjCh_Init
76 )
77 {
78 	/* PRECONDITION */
79 	{
80 		GLOBALASSERT( pProjCh_Init );
81 	}
82 
83 	/* CODE */
84 	{
85 		AllocatedSize = (size_t) STRUTIL_SC_NumBytes
86 		(
87 			pProjCh_Init
88 		);
89 
90 		pProjCh_Val = new ProjChar[	AllocatedSize ];
91 		GLOBALASSERT( pProjCh_Val );
92 
93 		STRUTIL_SC_StrCpy
94 		(
95 			pProjCh_Val,
96 			pProjCh_Init
97 		);
98 
99 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
100 			// doesn't include NULL terminator
101 
102 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
103 
104 		while ( i>0 )
105 		{
106 			i = (FontIndex)(i-1);
107 
108 			IndexedFont* pFont = IndexedFont :: GetFont( i );
109 
110 			if ( pFont )
111 			{
112 				R2Size[ i ] = pFont -> CalcSize
113 				(
114 					pProjCh_Val
115 				);
116 
117 				bCanRender[ i ] = pFont -> bCanRenderFully
118 				(
119 					pProjCh_Val
120 				);
121 			}
122 			else
123 			{
124 				R2Size[ i ] = r2size(0,0);
125 
126 				bCanRender[ i ] = No;
127 			}
128 		}
129 
130 		// Insert at head of list:
131 		{
132 			if ( pFirst )
133 			{
134 				pFirst -> pPrv = this;
135 			}
136 
137 			pNxt = pFirst;
138 			pPrv = NULL;
139 
140 			pFirst = this;
141 		}
142 	}
143 }
144 
SCString(signed int Number)145 SCString :: SCString
146 (
147 	signed int Number
148 )
149 {
150 	// forms a new string object that describes the number passed
151 	// standard decimal representation
152 
153 	/* PRECONDITION */
154 	{
155 	}
156 
157 	/* CODE */
158 	{
159 		ProjChar pProjCh_Init[ MAX_BYTES_IN_NUMERIC_STRING ];
160 
161 		sprintf
162 		(
163 			pProjCh_Init,
164 			"%i",
165 			(int)Number
166 		);
167 
168 		#if 0
169 		LOCALISEME();
170 		#endif
171 
172 		AllocatedSize = (size_t) STRUTIL_SC_NumBytes
173 		(
174 			pProjCh_Init
175 		);
176 
177 		pProjCh_Val = new ProjChar[	AllocatedSize ];
178 		GLOBALASSERT( pProjCh_Val );
179 			// this is always "owned" by the String
180 
181 		STRUTIL_SC_StrCpy
182 		(
183 			pProjCh_Val,
184 			pProjCh_Init
185 		);
186 
187 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
188 			// doesn't include NULL terminator
189 
190 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
191 
192 		while ( i>0 )
193 		{
194 			i = (FontIndex)(i-1);
195 
196 			IndexedFont* pFont = IndexedFont :: GetFont( i );
197 
198 			if ( pFont )
199 			{
200 				R2Size[ i ] = pFont -> CalcSize
201 				(
202 					pProjCh_Val
203 				);
204 
205 				bCanRender[ i ] = pFont -> bCanRenderFully
206 				(
207 					pProjCh_Val
208 				);
209 			}
210 			else
211 			{
212 				R2Size[ i ] = r2size(0,0);
213 
214 				bCanRender[ i ] = No;
215 			}
216 		}
217 
218 		// Insert at head of list:
219 		{
220 			if ( pFirst )
221 			{
222 				pFirst -> pPrv = this;
223 			}
224 
225 			pNxt = pFirst;
226 			pPrv = NULL;
227 
228 			pFirst = this;
229 		}
230 
231 	}
232 }
233 
SCString(unsigned int Number)234 SCString :: SCString
235 (
236 	unsigned int Number
237 )
238 {
239 	// forms a new string object that describes the number passed
240 	// standard decimal representation
241 
242 	/* PRECONDITION */
243 	{
244 	}
245 
246 	/* CODE */
247 	{
248 		ProjChar pProjCh_Init[ MAX_BYTES_IN_NUMERIC_STRING ];
249 
250 		sprintf
251 		(
252 			pProjCh_Init,
253 			"%u",
254 			Number
255 		);
256 
257 		#if 0
258 		LOCALISEME();
259 		#endif
260 
261 		AllocatedSize = (size_t) STRUTIL_SC_NumBytes
262 		(
263 			pProjCh_Init
264 		);
265 
266 		pProjCh_Val = new ProjChar[	AllocatedSize ];
267 		GLOBALASSERT( pProjCh_Val );
268 			// this is always "owned" by the String
269 
270 		STRUTIL_SC_StrCpy
271 		(
272 			pProjCh_Val,
273 			pProjCh_Init
274 		);
275 
276 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
277 			// doesn't include NULL terminator
278 
279 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
280 
281 		while ( i>0 )
282 		{
283 			i = (FontIndex)(i-1);
284 
285 			IndexedFont* pFont = IndexedFont :: GetFont( i );
286 
287 			if ( pFont )
288 			{
289 				R2Size[ i ] = pFont -> CalcSize
290 				(
291 					pProjCh_Val
292 				);
293 
294 				bCanRender[ i ] = pFont -> bCanRenderFully
295 				(
296 					pProjCh_Val
297 				);
298 			}
299 			else
300 			{
301 				R2Size[ i ] = r2size(0,0);
302 
303 				bCanRender[ i ] = No;
304 			}
305 		}
306 
307 		// Insert at head of list:
308 		{
309 			if ( pFirst )
310 			{
311 				pFirst -> pPrv = this;
312 			}
313 
314 			pNxt = pFirst;
315 			pPrv = NULL;
316 
317 			pFirst = this;
318 		}
319 
320 	}
321 }
322 
SCString(float Number)323 SCString :: SCString
324 (
325 	float Number
326 )
327 {
328 	/* PRECONDITION */
329 	{
330 	}
331 
332 	/* CODE */
333 	{
334 		ProjChar pProjCh_Init[ MAX_BYTES_IN_NUMERIC_STRING ];
335 
336 		sprintf
337 		(
338 			pProjCh_Init,
339 			"%6f",
340 			Number
341 		);
342 
343 		#if 0
344 		LOCALISEME();
345 		#endif
346 
347 		AllocatedSize = (size_t) STRUTIL_SC_NumBytes
348 		(
349 			pProjCh_Init
350 		);
351 
352 		pProjCh_Val = new ProjChar[	AllocatedSize ];
353 		GLOBALASSERT( pProjCh_Val );
354 			// this is always "owned" by the String
355 
356 		STRUTIL_SC_StrCpy
357 		(
358 			pProjCh_Val,
359 			pProjCh_Init
360 		);
361 
362 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
363 			// doesn't include NULL terminator
364 
365 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
366 
367 		while ( i>0 )
368 		{
369 			i = (FontIndex)(i-1);
370 
371 			IndexedFont* pFont = IndexedFont :: GetFont( i );
372 
373 			if ( pFont )
374 			{
375 				R2Size[ i ] = pFont -> CalcSize
376 				(
377 					pProjCh_Val
378 				);
379 
380 				bCanRender[ i ] = pFont -> bCanRenderFully
381 				(
382 					pProjCh_Val
383 				);
384 			}
385 			else
386 			{
387 				R2Size[ i ] = r2size(0,0);
388 
389 				bCanRender[ i ] = No;
390 			}
391 		}
392 
393 		// Insert at head of list:
394 		{
395 			if ( pFirst )
396 			{
397 				pFirst -> pPrv = this;
398 			}
399 
400 			pNxt = pFirst;
401 			pPrv = NULL;
402 
403 			pFirst = this;
404 		}
405 
406 	}
407 }
408 
409 
410 
SCString(ProjChar * pProjCh_Init,unsigned int Length)411 SCString :: SCString
412 (
413 	ProjChar* pProjCh_Init,
414 	unsigned int Length
415 )
416 {
417 	// Forms a string of length at most Length (with 1 extra for NULL-terminator)
418 
419 	/* PRECONDITION */
420 	{
421 		GLOBALASSERT( pProjCh_Init );
422 	}
423 
424 	/* CODE */
425 	{
426 		NumberOfCharacters = STRUTIL_SC_Strlen( pProjCh_Init );
427 			// doesn't include NULL terminator
428 
429 		if ( (unsigned)NumberOfCharacters > Length )
430 		{
431 			NumberOfCharacters = Length;
432 		}
433 
434 		AllocatedSize = (size_t) STRUTIL_SC_NumBytes
435 		(
436 			pProjCh_Init
437 		);
438 
439 		{
440 			size_t TruncSize = sizeof(ProjChar) * (Length + 1);
441 
442 			if (AllocatedSize > TruncSize )
443 			{
444 				AllocatedSize = TruncSize;
445 			}
446 		}
447 
448 		pProjCh_Val = new ProjChar[	AllocatedSize ];
449 		GLOBALASSERT( pProjCh_Val );
450 			// this is always "owned" by the String
451 
452 		STRUTIL_SC_SafeCopy
453 		(
454 			pProjCh_Val,
455 			(NumberOfCharacters+1),
456 
457 			pProjCh_Init
458 		);
459 
460 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
461 
462 		while ( i>0 )
463 		{
464 			i = (FontIndex)(i-1);
465 
466 			IndexedFont* pFont = IndexedFont :: GetFont( i );
467 
468 			if ( pFont )
469 			{
470 				R2Size[ i ] = pFont -> CalcSize
471 				(
472 					pProjCh_Val
473 				);
474 
475 				bCanRender[ i ] = pFont -> bCanRenderFully
476 				(
477 					pProjCh_Val
478 				);
479 			}
480 			else
481 			{
482 				R2Size[ i ] = r2size(0,0);
483 
484 				bCanRender[ i ] = No;
485 			}
486 		}
487 
488 		// Insert at head of list:
489 		{
490 			if ( pFirst )
491 			{
492 				pFirst -> pPrv = this;
493 			}
494 
495 			pNxt = pFirst;
496 			pPrv = NULL;
497 
498 			pFirst = this;
499 		}
500 
501 	}
502 }
503 
504 
SCString(SCString * pStringObj_0,SCString * pStringObj_1)505 SCString :: SCString
506 (
507 	SCString* pStringObj_0,
508 	SCString* pStringObj_1
509 )
510 {
511 	// forms a new string object by concatenating the strings in 0
512 	// and 1
513 
514 	/* PRECONDITION */
515 	{
516 		GLOBALASSERT( pStringObj_0 );
517 		GLOBALASSERT( pStringObj_1 );
518 	}
519 
520 	/* CODE */
521 	{
522 		ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh();
523 		GLOBALASSERT( pProjCh_Init_0 );
524 
525 		ProjChar* pProjCh_Init_1 = pStringObj_1 -> pProjCh();
526 		GLOBALASSERT( pProjCh_Init_1 );
527 
528 		AllocatedSize = (size_t)
529 		(
530 			STRUTIL_SC_NumBytes
531 			(
532 				pProjCh_Init_0
533 			)
534 			+
535 			STRUTIL_SC_NumBytes
536 			(
537 				pProjCh_Init_1
538 			)
539 			- sizeof(ProjChar)	// only one null terminator needed
540 		);
541 
542 		pProjCh_Val = new ProjChar[	AllocatedSize ];
543 		GLOBALASSERT( pProjCh_Val );
544 
545 			// this is always "owned" by the String
546 		STRUTIL_SC_FastCat
547 		(
548 			pProjCh_Val,
549 			pProjCh_Init_0,
550 			pProjCh_Init_1
551 		);
552 
553 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
554 			// doesn't include NULL terminator
555 
556 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
557 
558 		while ( i>0 )
559 		{
560 			i = (FontIndex)(i-1);
561 
562 			R2Size[ i ] = pStringObj_0 -> CalcSize( i );
563 			R2Size[ i ] . w += pStringObj_1 -> CalcSize( i ) . w;
564 
565 			bCanRender[ i ] =
566 			(
567 				pStringObj_0 -> bCanRenderFully( i )
568 				&&
569 				pStringObj_1 -> bCanRenderFully( i )
570 			);
571 		}
572 
573 		// Insert at head of list:
574 		{
575 			if ( pFirst )
576 			{
577 				pFirst -> pPrv = this;
578 			}
579 
580 			pNxt = pFirst;
581 			pPrv = NULL;
582 
583 			pFirst = this;
584 		}
585 
586 	}
587 }
588 
589 
SCString(SCString * pStringObj_0,SCString * pStringObj_1,SCString * pStringObj_2)590 SCString :: SCString
591 (
592 	SCString* pStringObj_0,
593 	SCString* pStringObj_1,
594 	SCString* pStringObj_2
595 )
596 {
597 	// forms a new string object by concatenating the strings in 0, 1 and 2
598 
599 	/* PRECONDITION */
600 	{
601 		GLOBALASSERT( pStringObj_0 );
602 		GLOBALASSERT( pStringObj_1 );
603 		GLOBALASSERT( pStringObj_2 );
604 	}
605 
606 	/* CODE */
607 	{
608 		// Insert at head of list:
609 		{
610 			if ( pFirst )
611 			{
612 				pFirst -> pPrv = this;
613 			}
614 
615 			pNxt = pFirst;
616 			pPrv = NULL;
617 
618 			pFirst = this;
619 		}
620 
621 		SCString* pStringObj_Intermediate = new SCString
622 		(
623 			pStringObj_1,
624 			pStringObj_2
625 		);
626 
627 		ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh();
628 		GLOBALASSERT( pProjCh_Init_0 );
629 
630 		ProjChar* pProjCh_Intermediate = pStringObj_Intermediate -> pProjCh();
631 		GLOBALASSERT( pProjCh_Intermediate );
632 
633 		AllocatedSize = (size_t)
634 		(
635 			STRUTIL_SC_NumBytes
636 			(
637 				pProjCh_Init_0
638 			)
639 			+
640 			STRUTIL_SC_NumBytes
641 			(
642 				pProjCh_Intermediate
643 			)
644 			- sizeof(ProjChar)	// only one null terminator needed
645 		);
646 
647 		pProjCh_Val = new ProjChar[	AllocatedSize ];
648 		GLOBALASSERT( pProjCh_Val );
649 			// this is always "owned" by the String
650 		STRUTIL_SC_FastCat
651 		(
652 			pProjCh_Val,
653 			pProjCh_Init_0,
654 			pProjCh_Intermediate
655 		);
656 
657 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
658 		// doesn't include NULL terminator
659 
660 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
661 
662 		while ( i>0 )
663 		{
664 			i = (FontIndex)(i-1);
665 
666 			R2Size[ i ] = pStringObj_0 -> CalcSize( i );
667 			R2Size[ i ] . w +=
668 			(
669 				pStringObj_1 -> CalcSize( i ) . w
670 				+
671 				pStringObj_2 -> CalcSize( i ) . w
672 			);
673 
674 			bCanRender[ i ] =
675 			(
676 				pStringObj_0 -> bCanRenderFully( i )
677 				&&
678 				pStringObj_1 -> bCanRenderFully( i )
679 				&&
680 				pStringObj_2 -> bCanRenderFully( i )
681 			);
682 		}
683 
684 		pStringObj_Intermediate -> R_Release();
685 	}
686 }
687 
SCString(SCString * pStringObj_0,SCString * pStringObj_1,SCString * pStringObj_2,SCString * pStringObj_3)688 SCString :: SCString
689 (
690 	SCString* pStringObj_0,
691 	SCString* pStringObj_1,
692 	SCString* pStringObj_2,
693 	SCString* pStringObj_3
694 )
695 {
696 	/* PRECONDITION */
697 	{
698 		GLOBALASSERT( pStringObj_0 );
699 		GLOBALASSERT( pStringObj_1 );
700 		GLOBALASSERT( pStringObj_2 );
701 		GLOBALASSERT( pStringObj_3 );
702 	}
703 
704 	/* CODE */
705 	{
706 		// Insert at head of list:
707 		{
708 			if ( pFirst )
709 			{
710 				pFirst -> pPrv = this;
711 			}
712 
713 			pNxt = pFirst;
714 			pPrv = NULL;
715 
716 			pFirst = this;
717 		}
718 
719 		SCString* pStringObj_Intermediate = new SCString
720 		(
721 			pStringObj_1,
722 			pStringObj_2,
723 			pStringObj_3
724 		);
725 
726 		ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh();
727 		GLOBALASSERT( pProjCh_Init_0 );
728 
729 		ProjChar* pProjCh_Intermediate = pStringObj_Intermediate -> pProjCh();
730 		GLOBALASSERT( pProjCh_Intermediate );
731 
732 		AllocatedSize = (size_t)
733 		(
734 			STRUTIL_SC_NumBytes
735 			(
736 				pProjCh_Init_0
737 			)
738 			+
739 			STRUTIL_SC_NumBytes
740 			(
741 				pProjCh_Intermediate
742 			)
743 			- sizeof(ProjChar)	// only one null terminator needed
744 		);
745 
746 		pProjCh_Val = new ProjChar[	AllocatedSize ];
747 		GLOBALASSERT( pProjCh_Val );
748 			// this is always "owned" by the String
749 		STRUTIL_SC_FastCat
750 		(
751 			pProjCh_Val,
752 			pProjCh_Init_0,
753 			pProjCh_Intermediate
754 		);
755 
756 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
757 		// doesn't include NULL terminator
758 
759 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
760 
761 		while ( i>0 )
762 		{
763 			i = (FontIndex)(i-1);
764 
765 			R2Size[ i ] = pStringObj_0 -> CalcSize( i );
766 			R2Size[ i ] . w +=
767 			(
768 				pStringObj_1 -> CalcSize( i ) . w
769 				+
770 				pStringObj_2 -> CalcSize( i ) . w
771 				+
772 				pStringObj_3 -> CalcSize( i ) . w
773 			);
774 
775 			bCanRender[ i ] =
776 			(
777 				pStringObj_0 -> bCanRenderFully( i )
778 				&&
779 				pStringObj_1 -> bCanRenderFully( i )
780 				&&
781 				pStringObj_2 -> bCanRenderFully( i )
782 				&&
783 				pStringObj_3 -> bCanRenderFully( i )
784 			);
785 		}
786 
787 		pStringObj_Intermediate -> R_Release();
788 	}
789 }
790 
791 
SCString(SCString * pStringObj_0,SCString * pStringObj_1,SCString * pStringObj_2,SCString * pStringObj_3,SCString * pStringObj_4)792 SCString :: SCString
793 (
794 	SCString* pStringObj_0,
795 	SCString* pStringObj_1,
796 	SCString* pStringObj_2,
797 	SCString* pStringObj_3,
798 	SCString* pStringObj_4
799 )
800 {
801 	/* PRECONDITION */
802 	{
803 		GLOBALASSERT( pStringObj_0 );
804 		GLOBALASSERT( pStringObj_1 );
805 		GLOBALASSERT( pStringObj_2 );
806 		GLOBALASSERT( pStringObj_3 );
807 		GLOBALASSERT( pStringObj_4 );
808 	}
809 
810 	/* CODE */
811 	{
812 		// Insert at head of list:
813 		{
814 			if ( pFirst )
815 			{
816 				pFirst -> pPrv = this;
817 			}
818 
819 			pNxt = pFirst;
820 			pPrv = NULL;
821 
822 			pFirst = this;
823 		}
824 
825 		SCString* pStringObj_Intermediate = new SCString
826 		(
827 			pStringObj_1,
828 			pStringObj_2,
829 			pStringObj_3,
830 			pStringObj_4
831 		);
832 
833 		ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh();
834 		GLOBALASSERT( pProjCh_Init_0 );
835 
836 		ProjChar* pProjCh_Intermediate = pStringObj_Intermediate -> pProjCh();
837 		GLOBALASSERT( pProjCh_Intermediate );
838 
839 		AllocatedSize = (size_t)
840 		(
841 			STRUTIL_SC_NumBytes
842 			(
843 				pProjCh_Init_0
844 			)
845 			+
846 			STRUTIL_SC_NumBytes
847 			(
848 				pProjCh_Intermediate
849 			)
850 			- sizeof(ProjChar)	// only one null terminator needed
851 		);
852 
853 		pProjCh_Val = new ProjChar[	AllocatedSize ];
854 		GLOBALASSERT( pProjCh_Val );
855 			// this is always "owned" by the String
856 		STRUTIL_SC_FastCat
857 		(
858 			pProjCh_Val,
859 			pProjCh_Init_0,
860 			pProjCh_Intermediate
861 		);
862 
863 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
864 		// doesn't include NULL terminator
865 
866 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
867 
868 		while ( i>0 )
869 		{
870 			i = (FontIndex)(i-1);
871 
872 			R2Size[ i ] = pStringObj_0 -> CalcSize( i );
873 			R2Size[ i ] . w +=
874 			(
875 				pStringObj_1 -> CalcSize( i ) . w
876 				+
877 				pStringObj_2 -> CalcSize( i ) . w
878 				+
879 				pStringObj_3 -> CalcSize( i ) . w
880 				+
881 				pStringObj_4 -> CalcSize( i ) . w
882 			);
883 
884 			bCanRender[ i ] =
885 			(
886 				pStringObj_0 -> bCanRenderFully( i )
887 				&&
888 				pStringObj_1 -> bCanRenderFully( i )
889 				&&
890 				pStringObj_2 -> bCanRenderFully( i )
891 				&&
892 				pStringObj_3 -> bCanRenderFully( i )
893 				&&
894 				pStringObj_4 -> bCanRenderFully( i )
895 			);
896 		}
897 
898 		pStringObj_Intermediate -> R_Release();
899 	}
900 }
901 
902 
SCString(List<ProjChar> List_ProjChar)903 SCString :: SCString
904 (
905 	List<ProjChar> List_ProjChar
906 )
907 {
908 	{
909 		AllocatedSize = (size_t) (List_ProjChar . size() + 1) * sizeof(ProjChar);
910 
911 		pProjCh_Val = new ProjChar[	AllocatedSize ];
912 		GLOBALASSERT( pProjCh_Val );
913 
914 		#if 1
915 		{
916 			ProjChar* pDst = pProjCh_Val;
917 
918 			for
919 			(
920 				LIF<ProjChar> oi(&(List_ProjChar));
921 				!oi.done();
922 				oi.next()
923 			)
924 			{
925 				*(pDst++) = oi();
926 			}
927 
928 			// Write terminator:
929 			*pDst = 0;
930 		}
931 		#else
932 		STRUTIL_SC_StrCpy
933 		(
934 			pProjCh_Val,
935 			pProjCh_Init
936 		);
937 		#endif
938 
939 		NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1;
940 			// doesn't include NULL terminator
941 
942 		FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS;
943 
944 		while ( i>0 )
945 		{
946 			i = (FontIndex)(i-1);
947 
948 			IndexedFont* pFont = IndexedFont :: GetFont( i );
949 
950 			if ( pFont )
951 			{
952 				R2Size[ i ] = pFont -> CalcSize
953 				(
954 					pProjCh_Val
955 				);
956 
957 				bCanRender[ i ] = pFont -> bCanRenderFully
958 				(
959 					pProjCh_Val
960 				);
961 			}
962 			else
963 			{
964 				R2Size[ i ] = r2size(0,0);
965 
966 				bCanRender[ i ] = No;
967 			}
968 		}
969 
970 		// Insert at head of list:
971 		{
972 			if ( pFirst )
973 			{
974 				pFirst -> pPrv = this;
975 			}
976 
977 			pNxt = pFirst;
978 			pPrv = NULL;
979 
980 			pFirst = this;
981 		}
982 	}
983 
984 }
985 
UpdateAfterFontChange(FontIndex I_Font_Changed)986 /*static*/ void SCString :: UpdateAfterFontChange( FontIndex I_Font_Changed )
987 {
988 	// called by the font code whenever fonts are loaded/unloaded
989 
990 	/* PRECONDITION */
991 	{
992 		GLOBALASSERT( I_Font_Changed < IndexedFonts_MAX_NUMBER_OF_FONTS );
993 	}
994 
995 	/* CODE */
996 	{
997 		IndexedFont* pFont = IndexedFont :: GetFont( I_Font_Changed );
998 
999 		SCString* pSCString = pFirst;
1000 
1001 		while ( pSCString )
1002 		{
1003 			if ( pFont )
1004 			{
1005 				pSCString -> R2Size[ I_Font_Changed ] = pFont -> CalcSize
1006 				(
1007 					pSCString -> pProjCh_Val
1008 				);
1009 
1010 				pSCString -> bCanRender[ I_Font_Changed ] = pFont -> bCanRenderFully
1011 				(
1012 					pSCString -> pProjCh_Val
1013 				);
1014 			}
1015 			else
1016 			{
1017 				pSCString -> R2Size[ I_Font_Changed ] = r2size(0,0);
1018 
1019 				pSCString -> bCanRender[ I_Font_Changed ] = No;
1020 			}
1021 
1022 			pSCString = pSCString -> pNxt;
1023 		}
1024 	}
1025 }
1026 
Parse(ProjChar * pProjChar_Start)1027 /*static*/ List<SCString*> SCString :: Parse
1028 (
1029 	ProjChar* pProjChar_Start
1030 )
1031 {
1032 	// takes a string and builds a list of new SCStrings, in which
1033 	// each string in the list consists of non-whitespace characters from
1034 	// the input, and the whitespace is used to separate individual
1035 	// strings
1036 
1037 	// I call the strings "words"
1038 
1039 	/* PRECONDITION */
1040 	{
1041 		GLOBALASSERT( pProjChar_Start );
1042 	}
1043 
1044 	/* CODE */
1045 	{
1046 		List<SCString*> List_Return;
1047 
1048 		ProjChar* pProjChar_Iterate = pProjChar_Start;
1049 		int NumCharsNonWhitespace = 0;
1050 
1051 		while
1052 		(
1053 			*pProjChar_Iterate
1054 		)
1055 		{
1056 			if
1057 			(
1058 				*pProjChar_Iterate == ' '
1059 			)
1060 			{
1061 				// Whitespace:
1062 				if ( NumCharsNonWhitespace > 0 )
1063 				{
1064 					// End of a word; add the string to the list:
1065 					List_Return . add_entry
1066 					(
1067 						new SCString
1068 						(
1069 							pProjChar_Start,
1070 							NumCharsNonWhitespace
1071 						)
1072 					);
1073 					NumCharsNonWhitespace = 0;
1074 				}
1075 				else
1076 				{
1077 					// Already processing a block of whitespace; do nothing
1078 				}
1079 			}
1080 			else
1081 			{
1082 				// Non-whitespace:
1083 				if ( NumCharsNonWhitespace > 0 )
1084 				{
1085 					// In the middle of a word:
1086 				}
1087 				else
1088 				{
1089 					// Start of a word:
1090 					pProjChar_Start = pProjChar_Iterate;
1091 				}
1092 
1093 				NumCharsNonWhitespace++;
1094 
1095 			}
1096 
1097 			pProjChar_Iterate++;
1098 		}
1099 
1100 		// End of the string; flush any remaining whitespace:
1101 		if ( NumCharsNonWhitespace > 0 )
1102 		{
1103 			List_Return . add_entry
1104 			(
1105 				new SCString
1106 				(
1107 					pProjChar_Start,
1108 					NumCharsNonWhitespace
1109 				)
1110 			);
1111 		}
1112 
1113 		return List_Return;
1114 	}
1115 }
1116 
1117 
1118 //private:
~SCString()1119 SCString :: ~SCString()
1120 {
1121 	/* PRECONDITION */
1122 	{
1123 		GLOBALASSERT( pProjCh_Val );
1124 	}
1125 
1126 	/* CODE */
1127 	{
1128 		delete[] pProjCh_Val;
1129 
1130 		// Remove from list:
1131 		{
1132 			if ( pFirst == this )
1133 			{
1134 				pFirst = pNxt;
1135 			}
1136 			else
1137 			{
1138 				pPrv -> pNxt = pNxt;
1139 			}
1140 
1141 			if (pNxt)
1142 			{
1143 				pNxt -> pPrv = pPrv;
1144 			}
1145 		}
1146 
1147 	}
1148 }
1149