tt/lib: remove register keyword
[oweals/cde.git] / cde / lib / tt / lib / util / tt_string.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $XConsortium: tt_string.C /main/5 1996/09/24 10:06:12 drk $                                                       
28 /* @(#)tt_string.C      1.61 95/02/27
29  *
30  * tt_string.cc
31  *
32  * Copyright (c) 1990 by Sun Microsystems, Inc.
33  * 
34  * Implementation of _Tt_string class operations.
35  * There are two classes involved: _Tt_string, which is just a pointer
36  * to _Tt_string_buf, which includes ref counts, the length of the
37  * string, and a pointer to the (malloc'ed) actual contents.
38  * Though _Tt_string_buf is the actual "guts" of a string, clients
39  * never refer to it, but always use _Tt_string.  _Tt_string_buf
40  * therefore has no public members.
41  *
42  * We always malloc one more byte than specified in the _Tt_string_buf
43  * length member, to ensure that there's room for a terminating zero byte.
44  * This means we can just hand back the _Tt_string_buf contents pointer
45  * to clients wanting a char * for passing to other routines (e.g. printf.)
46  * 
47  * This also makes the internal length field the same as strlen.
48  */
49
50 #include <string.h>
51 #include <memory.h>
52 #if defined(ultrix)
53 #include <rpc/types.h>
54 #endif
55 #include <stdlib.h>
56 #include <ctype.h>
57 #if defined(__linux__) || defined(CSRG_BASED) || defined(sun)
58 #include <wctype.h>
59 #endif
60 #include "util/tt_string.h"
61 #include "util/tt_assert.h"
62 #include "util/tt_xdr_utils.h"
63 #include "util/tt_xdr_version.h"
64 #include "util/tt_iostream.h"
65 #include "util/tt_port.h"
66 #include "util/tt_global_env.h"
67
68 implement_list_of(_Tt_string_buf)
69
70 typedef bool_t (*local_xdrproc_t)(XDR *, caddr_t *);
71
72 //
73 // The plain constructor for _Tt_string_buf just creates a null
74 // pointer. (Not a null string, which would be a pointer to a zero byte.)
75 //
76 /* 
77  * _Tt_string_buf::
78  * _Tt_string_buf()
79  * {
80  *      content = (char *)0;
81  *      length = 0;
82  * }
83  */
84 //
85 // The _Tt_string_buf copy constructor should not be used much, since
86 // generally pointers to _Tt_string_buf's are passed around.
87 //
88
89 _Tt_string_buf::
90 _Tt_string_buf(const _Tt_string_buf& s)
91 {
92         content = (char *)malloc(s.length+1);
93         length = s.length;
94         memcpy(content,s.content,length+1);
95 }
96
97 //
98 // The _Tt_string_buf destructor frees the actual string storage.
99 //
100
101 _Tt_string_buf::
102 ~_Tt_string_buf()
103 {
104         if (content != (char *)0) {
105                 (void)free((MALLOCTYPE *)content);
106         }
107 }
108
109 void _Tt_string_buf::
110 set(const unsigned char *s, int len)
111 {
112         length = len;
113         if ((s != (const unsigned char*) 0) && (len >= 0)) {
114                 content = (char *)malloc(len+1);
115                 memcpy(content,s,len);
116                 content[len] = '\0';
117         } else {
118                 content = (char *)0;
119         }
120 }
121
122 // a non-member function for use when you have a char *, but don't
123 // yet have a _Tt_string.
124 void
125 _tt_print_escaped_string(const _Tt_ostream &os, const char *s, int length,
126                          int max_print_width, int quote_it)
127 {
128         int i, count;
129
130         static int width_inited = 0;
131         static int _max_print_width;
132         if (! width_inited) {
133                 width_inited = 1;
134                 _max_print_width = 40;
135                 char *s = _tt_get_first_set_env_var(2, "TT_ARG_TRACE_WIDTH", 
136                                                        "_SUN_TT_ARG_TRACE_WIDTH");
137                 if (s != 0) {
138                         _max_print_width = atoi(s);
139                 }
140         }
141         switch (max_print_width) {
142             case _Tt_string_unlimited:
143                 max_print_width = 80000;
144                 break;
145             case _Tt_string_user_width:
146                 max_print_width = _max_print_width;
147                 break;
148         }
149         if (s == 0) {
150                 os << "(null)";
151         } else {
152                 wchar_t wc;
153                 int n;
154
155                 if (quote_it) {
156                         os << '"';
157                 }
158
159                 for (count=0, i=0; count < max_print_width && i < length;) {
160
161                         if (length - i >= MB_LEN_MAX) {
162
163                                 if ((n = mbtowc(&wc, &s[i], MB_LEN_MAX)) != -1) {
164                                 // multi-byte character buffer. Interpret it appropriately.
165
166                                         if (iswprint(wc) || iswspace(wc)) {
167                                                 count += (n == 0) ? 1 : n;
168
169                                                 // We do it this way rather than through
170                                                 // _Tt_iostream operator<<  method because
171                                                 // wchar_t is equivalent  to a long and the
172                                                 // compiler doesn't know which method to use.
173                                                 os.sprintf(MB_LEN_MAX, "%C", wc);
174                                         } else {
175                                                 count += (3  + ((n == 0) ? 1 : n));
176
177                                                 // don't print past limit, even a little.
178                                                 if (count < max_print_width) {
179                                                         os.sprintf(10, "\\%03C", wc);
180                                                 }
181                                         }
182
183                                         i += (n == 0) ? 1 : n;
184
185                                         continue;
186                                 }
187                         }
188
189                         // non-multi-byte character buffer...
190                         if (isprint((unsigned char) s[i]) ||
191                             isspace((unsigned char) s[i])) {
192                                 count += 1;
193                                 os << s[i];
194                         } else {
195                                 count += 3;
196
197                                 // don't print past limit, even a little.
198                                 if (count < max_print_width) {
199                                         os.sprintf(10, "\\%03o", (unsigned char) s[i]);
200                                 }
201                         }
202                         i++;
203                 }
204
205                 if (quote_it) {
206                         os << '"';
207                 }
208
209                 if (i < length) {
210                         os << "[...]";
211                 }
212         }
213 }
214
215
216 // print on a string is mainly for debugging. So we limit the number
217 // of characters printed, and print escaped octal (\ddd) for nongraphic
218 // characters.
219 void _Tt_string_buf::
220 print(const _Tt_ostream &os, int max_print_width, int quote_it) const
221 {
222         _tt_print_escaped_string(os, content, length, max_print_width,
223                          quote_it);
224 }
225
226 bool_t _Tt_string_buf::
227 xdr(XDR *xdrs)
228 {
229         if (_tt_global->xdr_version() == 1) {
230                 return(xdr_1(xdrs));
231         } else {
232                 return(xdr_2(xdrs));
233         }
234 }
235
236
237 bool_t _Tt_string_buf::
238 xdr_1(XDR *xdrs)
239 {
240         char    *sp;
241         u_int   u_length;
242
243         if (xdr_int(xdrs, &length)) {
244                 if (length > 0) {
245                         if (xdrs->x_op == XDR_DECODE) {
246                                 sp =  (char *)malloc(length + 1);
247                         } else {
248                                 sp = content;
249                                 u_length = length;
250                         }
251                         if (xdr_bytes(xdrs, &sp, &u_length, length)) {
252                                 if (xdrs->x_op == XDR_DECODE) {
253                                         if (content != (char *)0) {
254                                                 (void)free((MALLOCTYPE *)content);
255                                         }
256                                         content = sp;
257                                         content[length] = '\0';
258                                 }
259                         } else {
260                                 // couldn't xdr content field
261                                 return 0;
262                         }
263                 }
264                 return 1;
265         } else {
266                 // couldn't xdr length field
267                 return 0;
268         }
269 }
270
271
272 bool_t _Tt_string_buf::
273 xdr_2(XDR *xdrs)
274 {
275         char    *sp;
276         int      len = length;
277
278         if (content == (char *)0) len = -1;
279
280         if (xdr_int(xdrs, &len)) {
281                 // if a regular string...
282                 if (len > 0) {
283                         if (xdrs->x_op == XDR_DECODE) {
284                                 sp = (char *)malloc(len + 1);
285                         } else {
286                                 sp = content;
287                         }
288
289                         if (xdr_opaque(xdrs, (caddr_t)sp, len)) {
290                                 if (xdrs->x_op == XDR_DECODE) {
291                                         if (content != (char *)0) {
292                                                 (void)free((MALLOCTYPE *)content);
293                                         }
294                                         content = sp;
295                                         content[len] = '\0';
296                                         length = len;
297                                 }
298                         } else {
299                                 // couldn't xdr content field
300                                 return 0;
301                         }
302                 }
303                 // if an empty string ("")...
304                 else if (len == 0) {
305                         if (xdrs->x_op == XDR_DECODE) {
306                                 if (content != (char *)0) {
307                                         (void)free((MALLOCTYPE *)content);
308                                 }
309                                 content = (char *)malloc(1);
310                                 *content = '\0';
311                                 length = 0;
312                         }
313                 }
314                 // if a NULL string...
315                 else if (len == -1) {
316                         if (xdrs->x_op == XDR_DECODE) {
317                                 if (content != (char *)0) {
318                                         (void)free((MALLOCTYPE *)content);
319                                 }
320                                 content = (char *)0;
321                                 length = 0;
322                         }
323                 }
324
325                 return 1;
326         } else {
327                 // couldn't xdr length field
328                 return 0;
329         }
330 }
331
332
333 //
334 // The plain _Tt_string constructor creates a null string.
335 //
336
337 _Tt_string::
338 _Tt_string()
339 {
340         if (_tt_global != 0) {
341                 *(_Tt_string_buf_ptr *)this=_tt_global->universal_null_string;
342         }
343         else {
344                 *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
345         }
346 }
347
348 //
349 // The _Tt_string copy constructor is sure to call the parent copy constructor
350 //
351 _Tt_string::
352 _Tt_string(const _Tt_string &s) : _Tt_string_buf_ptr(s)
353 {
354 }
355
356 //
357 //  A _Tt_string can be constructed from a "char *" C string.
358 //
359 _Tt_string::
360 _Tt_string(const char *s)
361 {
362         *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
363         if (s != (char *)0) {
364                 (*this)->length = strlen(s);
365                 (*this)->content = (char *)malloc((*this)->length+1);
366                 memcpy((*this)->content,s,(*this)->length);
367                 ((*this)->content)[(*this)->length] = '\0';
368         } else {
369                 (*this)->length = 0;
370                 (*this)->content = (char *)0;
371         }
372 }
373
374 //
375 //  A special constructor builds a _Tt_string containing "n" bytes,
376 //  not initialized to anything.  
377 //
378 _Tt_string::
379 _Tt_string(int n)
380 {
381         // Trying to create a string of negative length is arguably
382         // a fatal error, but it's really obnoxious to have
383         // constructors fail.  So if we get a negative argument,
384         // just build a null string.
385
386         if (n<0) {
387                 n = 0;
388         }
389         
390         *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
391         (*this)->length = n;
392         (*this)->content = (char *)malloc(n+1);
393         (*this)->content[n] = '\0';
394 }
395
396 //
397 // A _Tt_string can be constructed from a bytestring.
398 //
399 _Tt_string::
400 _Tt_string(const unsigned char *s, int len)
401 {
402         *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
403         (*(_Tt_string_buf_ptr *)this)->set(s, len);
404 }
405
406
407 _Tt_string::
408 ~_Tt_string()
409 {
410 }
411
412 //
413 // Assigning from a char * string is supported, copying the string.
414 //
415 _Tt_string& _Tt_string::
416 operator=(const char * s)
417 {
418         _Tt_string newstring(s);
419         *(_Tt_string_buf_ptr *)this = newstring;
420         return *this;
421 }
422
423 //
424 // "set" is very like assignment, but takes a pointer and a string
425 // to handle bytestrings.
426 //
427 _Tt_string& _Tt_string::
428 set(const unsigned char * s, int n)
429 {
430         _Tt_string newstring(s,n);
431         *(_Tt_string_buf_ptr *)this = newstring;
432         return *this;
433 }
434
435 //
436 // Operator [] (subscripting) is overloaded to allow access to individual
437 // elements of the string.
438 //
439 const char& _Tt_string::
440 operator[](int offset) const
441 {
442         ASSERT(0<=offset && offset<length,"String subscript out of range");
443         return (*this)->content[offset];
444 }
445
446 char& _Tt_string::
447 operator[](int offset)
448 {
449         return (*this)->content[offset];
450 }
451
452 //
453 // operator char * (conversion to char *) returns the
454 // base string.
455 //
456 _Tt_string::
457 operator char*() const
458 {
459         return (*this)->content;
460 }
461
462 //
463 // operator const char * (conversion to const char *) returns the
464 // base string as a const.
465 //
466 _Tt_string::
467 operator const char*() const
468 {
469         return (const char *) ((*this)->content);
470 }
471
472 //
473 // left(n) returns a _Tt_string containing the first n characters
474 // of the string, or the string if there aren't that many.
475 //
476 _Tt_string _Tt_string::
477 left(int l) const
478 {
479         return mid(0,l);
480 }
481
482 //
483 // right(n) returns a _Tt_string containing the last n characters of the
484 // string, or the string if there aren't that many.
485 //
486 _Tt_string _Tt_string::
487 right(int l) const
488 {
489         return mid(len()-l,l);
490 }
491
492 //
493 // mid(o,l) returns a _Tt_string containing the l characters of the
494 // string starting at position o (zero-based.)
495 //
496 _Tt_string _Tt_string::
497 mid(int o, int l) const
498 {
499         ASSERT(o>=0 && l>=0,"Invalid argument");
500         if (o+l>len()) {
501                 l = len() - o;
502         }
503
504         _Tt_string result(l);
505
506         for (int i=0;i<l;++i) {
507                 result[i] = (*this)[i+o];
508         }
509         return result;
510 }
511
512 _Tt_string _Tt_string::
513 split(int i, _Tt_string &prefix) const
514 {
515         if (i < 0) {
516                 prefix = 0;
517                 return *this;
518         } else {
519                 prefix = mid(0,i);
520                 return mid(i+1,len()-i-1);
521         }
522 }
523
524 //
525 // split(c,prefix) finds the first occurrence of character c in
526 // this string.  All characters up to (but not including) c are
527 // returned as parameter "prefix"; the rest of the string (after c,
528 // but not including c) are returned as the function result.
529 // If the character does not include character c, prefix is returned
530 // as null and this string is returned as the result.
531 //
532 _Tt_string _Tt_string::
533 split(char c, _Tt_string &prefix) const
534 {
535         return split( index(c), prefix );
536 }
537
538 //
539 // Ditto, for string s instead of char c
540 //
541 _Tt_string _Tt_string::
542 split(const char *s, _Tt_string &prefix) const
543 {
544         int i = index(s);
545         if (i<0) {
546                 prefix = "";
547                 return *this;
548         }
549         prefix = left(i);
550         return right(len()-i-strlen(s));
551 }
552
553 //
554 // rsplit() is like split(), but it finds the _last_ occurrence of c
555 //
556 _Tt_string _Tt_string::
557 rsplit(char c, _Tt_string &prefix) const
558 {
559         return split( rindex(c), prefix );
560 }
561
562 //
563 // quote_nulls() returns a _Tt_string containing this string, with all
564 // embedded nulls replaced with "\0", and all "\" replaced
565 // with "\\".  This gives a string which can be safely treated as
566 // a "C" string, and which can be turned back into the original
567 // form with unquote_nulls().  The 
568 //
569 _Tt_string _Tt_string::
570 quote_nulls() const
571 {
572         int l = len();
573         char *result = (char *)malloc(2*l+1); // string will get at most 2x bigger
574         char *p = result;
575         _Tt_string r;
576
577
578         for (int i=0;i<l;++i) {
579                 int c = (*this)[i];
580                 if (c == '\0') {
581                         *p++ = '\\';
582                         *p++ = '0';
583                 } else if (c == '\\') {
584                         *p++ = '\\';
585                         *p++ = '\\';
586                 } else {
587                         *p++ = c;
588                 }
589         }
590         *p++ = '\0';
591
592         r = result;             // Put the value in a _Tt_string
593         (void)free((MALLOCTYPE *)result);
594
595         return r;
596 }
597 //
598 // unquote_nulls() returns a _Tt_string containing this string, with all
599 // backslash-quoted characters replaced by their equivalents, in particular
600 // \0 is replaced by a null.
601 //
602 _Tt_string _Tt_string::
603 unquote_nulls() const
604 {
605         int l;
606         unsigned char *result;
607         _Tt_string r;
608         unsigned char *p;
609         unsigned char *q;
610
611         l = len();
612         if (l==0) {
613                 r = "";
614                 return r;
615         }
616         result = (unsigned char *)malloc(l); // string will not grow
617
618         p = (unsigned char *)((*this)->content);
619         q = result;
620
621         while (*p) {
622                 if (*p == '\\') {
623                         ++p;
624                         ASSERT(*p,"Badly formed quote_null string");
625                         if (*p == '0') {
626                                 *q++ = '\0';
627                         } else {
628                                 *q++ = *p;
629                         }
630                 } else {
631                         *q++ = *p;
632                 }
633                 ++p;
634         }
635
636         r.set(result,q-result);
637         (void)free((MALLOCTYPE *)result);
638         return r;
639 }
640
641 //
642 // cat(s) returns a _Tt_string which is the concatenation of the
643 // object string and the argument string.
644 //
645 _Tt_string _Tt_string::
646 cat(const _Tt_string &s) const
647 {
648         _Tt_string      result(len()+s.len());
649         int             result_len = len() + s.len();
650
651         memcpy(result->content,(*this)->content,len());
652         memcpy(result->content+len(),s->content,s.len());
653         (result->content)[result_len] = '\0';
654         return result;
655 }
656
657 _Tt_string _Tt_string::
658 cat(char c) const
659 {
660         _Tt_string      result(len()+1);
661         int             result_len = len() + 1;
662         memcpy(result->content,(*this)->content,len());
663         (result->content)[result_len-1] = c;
664         (result->content)[result_len] = '\0';
665         return result;
666 }
667
668 _Tt_string _Tt_string::
669 cat(int i) const
670 {
671         return cat((long) i);
672 }
673
674 _Tt_string _Tt_string::
675 cat(unsigned int i) const
676 {
677         return cat((unsigned long) i);
678 }
679
680 _Tt_string _Tt_string::
681 cat(long i) const
682 {
683         char            buf[32];
684
685         sprintf(buf, "%ld", i);
686         return cat( buf );
687 }
688
689 _Tt_string _Tt_string::
690 cat(unsigned long i) const
691 {
692         char            buf[32];
693         sprintf(buf, "%lu", i);
694         return cat( buf );
695 }
696
697 //
698 // Return a new string, with each instance of old in this string replaced
699 // by with.  No rescan, so replacing "x" with "xx" does not loop.
700 //
701 _Tt_string _Tt_string::
702 replace(const char *old, const _Tt_string &with) const
703 {
704         _Tt_string result;
705         _Tt_string prefix;
706         _Tt_string remainder = *this;
707         int i;
708         int oldlen = strlen(old);
709
710         if (0==oldlen) {
711                 // arguably replacing the null string ought to insert
712                 // once between every old character and at beginning and
713                 // end.  But we don't bother.
714                 return (*this);
715         }
716         
717         do {
718                 i = remainder.index(old);
719                 if (i<0) {
720                         // no more matches found
721                         result = result.cat(remainder);
722                         remainder = "";
723                 } else {
724                         // Match found, replace it
725                         result = result.cat(remainder.left(i));
726                         result = result.cat(with);
727                         remainder = remainder.right(remainder.len()-i-oldlen);
728                 }
729         } while (remainder.len() > 0);
730         return result;
731 }
732
733 //
734 // len returns the length (strlen) of the object string
735 //
736 /* int _Tt_string::
737  * len() const
738  * {
739  *      return (*this)->length;
740  * }
741  */
742 // private cmp() compares and returns negative, 0, positive for object 
743 // less, equal, greater than arg.
744 // sadly, strcmp() can't be used here since we allow embedded
745 // nulls, and bcmp() only reports equal/not equal.
746 int _Tt_string::
747 cmp(const char *q, int qlen) const
748 {
749         char *p = (*this)->content;
750         int plen = len();
751         int pcmp;
752
753         if (0==p && 0==q) return 0;
754         if (0==p) return -1;
755         if (0==q) return 1;
756         if (qlen == -1) {
757                 qlen = strlen(q);
758         }
759         pcmp = memcmp(p, q, (plen < qlen) ? plen : qlen);
760         if (pcmp == 0 && plen > qlen) {
761                 return(1);
762         } else if (pcmp == 0 && plen < qlen) {
763                 return (-1);
764         } else {        
765                 return(pcmp);
766         }
767 }
768
769 /* XXX: old definition of cmp
770  * {    
771  * 
772  *      char *p = (*this)->content;
773  *      char *end;
774  *      int plen = len();
775  *      
776  *      // null pointers are treated as null strings, ignoring length.
777  *      if (0==p && 0==q) return 0;
778  *      if (0==p) return -1;
779  *      if (0==q) return 1;
780  * 
781  *      if (qlen == -1) {       // really comparing two _Tt_strings
782  *              qlen = strlen(q);
783  *      }
784  *      if (plen<qlen) {
785  *              end = p+plen;
786  *      } else {
787  *              end = p+qlen;
788  *      }
789  *      
790  *      while (p<end) {
791  *              if (*p<*q) return -1;
792  *              if (*p>*q) return +1;
793  *              ++p; ++q;
794  *      }
795  * 
796  *      // all the chars that are there compare, so the shorter string
797  *      // is the lesser.
798  * 
799  *      if (plen<qlen) return -1;
800  *      if (plen>qlen) return +1;
801  *      return 0;
802  * }
803  */
804
805
806 //
807 // index(c) returns the offset of the first occurence of char c within
808 // the object string.  Again, we can't use the system index() function.
809 // -1 is returned if the character doesn't exist in the object string.
810 //
811 int _Tt_string::
812 index(char c) const
813 {
814         if (len() == 0) {
815                 return -1;
816         }
817
818         char *p = (*this)->content;
819         char *end = p+len();
820         
821         while (p<end && *p!=c) ++p;
822         if (p==end) {
823                 return -1;
824         } else {
825                 return p-(*this)->content;
826         }
827 }
828
829 //
830 // If you really must search for null-containing strings, feel free
831 // to change this to take a const _Tt_string &.
832 //
833 int _Tt_string::
834 index(const char *s) const
835 {
836         if (s == 0 || len() == 0) {
837                 return -1;
838         }
839
840         char *p = (*this)->content;
841         char *end = p+len();
842         int slen = strlen(s);
843         int found = 0;
844
845         while ((! found) && (p < end - slen + 1)) {
846                 found = 1;
847                 for (int i = 0; i < slen; i++) {
848                         if (p[i] != s[i]) {
849                                 found = 0;
850                                 p++;
851                                 break;
852                         }
853                 }
854         }
855
856         if (! found) {
857                 return -1;
858         } else {
859                 return p-(*this)->content;
860         }
861 }
862
863
864 //
865 // rindex(c) returns the offset of the last occurence of char c within
866 // the object string.  Again, we can't use the system index() function.
867 // -1 is returned if the character doesn't exist in the object string.
868 //
869 int _Tt_string::
870 rindex(char c) const
871 {
872         if (len() == 0) {
873                 return -1;
874         }
875
876         char *beg = (*this)->content;
877         char *p = beg+len()-1;
878
879         while (p>=beg && *p!=c) --p;
880         if (p<beg) {
881                 return -1;
882         } else {
883                 return p-beg;
884         }
885 }
886
887 int _Tt_string::
888 strchr(char c) const
889 {
890   return index(c);
891 }
892
893 int _Tt_string::
894 strchr(const char *s) const
895 {
896   return index(s);
897 }
898
899 int _Tt_string::
900 strrchr(char c) const
901 {
902   return rindex(c);
903 }
904
905 int _Tt_string::
906 hash(int max_buckets) const
907 {
908         int hash_value = 0;
909         int length = len();
910         char *p = (*this)->content;
911         
912         while (length != 0) {
913                 hash_value += (length * *p++);
914                 length--;
915         }
916         hash_value = hash_value % max_buckets;
917         if (hash_value < 0) {
918                 hash_value = 0 - hash_value;
919         }
920         return (hash_value); /* hash to a bucket number */      
921 }
922
923
924 void _Tt_string::
925 print(const _Tt_ostream &os, int max, int quote_it) const
926 {
927         (*this)->print(os, max, quote_it);
928 }
929
930 // We used to handle the two flavors of print via defaulting, but
931 // that was too inconvenient in the debugger since "stdout" is a macro
932 // not a global, so trying to type stringname.print\(stdout\) was no good.
933 void _Tt_string::
934 print() const
935 {
936         (*this)->print(stdout);
937 }
938
939
940 //
941 // XDR support
942 //
943 bool_t _Tt_string::
944 xdr(XDR *xdrs)
945 {
946         if (_tt_global != 0 &&
947             (*(_Tt_string_buf_ptr *)this).c_pointer() ==
948             _tt_global->universal_null_string.c_pointer()) {
949                 *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
950         }
951
952         return((*this)->xdr(xdrs));
953 }
954
955 _Tt_string_list::
956 _Tt_string_list() : _Tt_string_buf_list()
957 {
958 }
959
960 _Tt_string_list::
961 _Tt_string_list(const _Tt_string_list &l) : _Tt_string_buf_list(l)
962 {
963 }
964
965 _Tt_string_list::
966 _Tt_string_list(const _Tt_string_buf_list &l) : _Tt_string_buf_list(l)
967 {
968 }
969
970
971 _Tt_string_list::
972 ~_Tt_string_list()
973 {
974 }
975
976 _Tt_string_list_ptr::
977 ~_Tt_string_list_ptr()
978 {
979 }
980
981 /* 
982  * Pointer assignment
983  */
984 _Tt_string_list_ptr &_Tt_string_list_ptr::
985 operator=(_Tt_string_list *s)
986 {
987         *(_Tt_string_buf_list_ptr *)this = (_Tt_string_buf_list *)s;
988         return *this;
989 }
990
991 _Tt_string_list_ptr &_Tt_string_list_ptr::
992 operator=(const _Tt_string_list_ptr &s)
993 {
994         return (_Tt_string_list_ptr &)_Tt_string_buf_list_ptr::operator=(s);
995 }
996
997 _Tt_string_list_cursor::
998 _Tt_string_list_cursor()
999 {
1000 }
1001
1002 _Tt_string_list_cursor::
1003 _Tt_string_list_cursor(const _Tt_string_list_ptr & l) : _Tt_string_buf_list_cursor(l)
1004 {
1005 }
1006
1007 _Tt_string_list_cursor::
1008 ~_Tt_string_list_cursor()
1009 {
1010 }
1011
1012 _Tt_string _Tt_string_list_cursor::
1013 operator *() const
1014 {
1015         return **(const _Tt_string_buf_list_cursor *)this;
1016 }
1017
1018
1019 _Tt_string _Tt_string_list_cursor::
1020 operator ->() const {
1021         return **(const _Tt_string_buf_list_cursor *)this;
1022 }
1023
1024 /* 
1025  * Encode data into an opaque Tt_string
1026  */
1027 int
1028 _tt_xdr_encode(xdrproc_t xdr_fn, void *data, _Tt_string &opaque_string)
1029 {
1030         unsigned long   datasize;
1031         XDR             xdrs;
1032
1033
1034         if (!(datasize = _tt_xdr_sizeof(xdr_fn, (char *)data))) {
1035                 return 0;
1036         }
1037         _Tt_string s((int)datasize);
1038         // create an in-memory xdr stream
1039         xdrmem_create(&xdrs, (char *)s, (u_int)datasize, XDR_ENCODE);
1040         // encode the data
1041         if (! (*(local_xdrproc_t)xdr_fn)(&xdrs, (caddr_t *)data)) {
1042                 return 0;
1043         }
1044         opaque_string = s;
1045         return 1;
1046 }
1047
1048 /* 
1049  * Decode data from an opaque _Tt_string
1050  */
1051 int
1052 _tt_xdr_decode(xdrproc_t xdr_fn, void *data, _Tt_string opaque_string)
1053 {
1054         char    *encoded = (char *)opaque_string;
1055         XDR     xdrs;
1056
1057         xdrmem_create(&xdrs, encoded, (u_int)opaque_string.len(), XDR_DECODE);
1058         if (! (*(local_xdrproc_t)xdr_fn)(&xdrs, (caddr_t *)data)) {
1059                 return 0;
1060         }
1061         return 1;
1062 }
1063
1064
1065 /* 
1066  * XDR encode or decode a _Tt_string
1067  */
1068 int
1069 tt_xdr_string(XDR *xdrs, _Tt_string *s)
1070 {
1071         return(s->xdr(xdrs));
1072 }
1073
1074 /* 
1075  * XDR encode or decode a _Tt_string_list
1076  */
1077 bool_t
1078 _tt_xdr_string_list(XDR *xdrs, _Tt_string_list_ptr *strings_ptr)
1079 {
1080         return (*strings_ptr)->xdr(xdrs);
1081 }
1082
1083 _Tt_string_list_ptr::
1084 _Tt_string_list_ptr() : _Tt_string_buf_list_ptr()
1085 {
1086 }
1087
1088 void    _tt_string_print(const _Tt_ostream &os, const _Tt_object *obj)
1089 {
1090         ((_Tt_string_buf *)obj)->print(os);
1091 }