2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
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
32 * Copyright (c) 1990 by Sun Microsystems, Inc.
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.
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.)
47 * This also makes the internal length field the same as strlen.
53 #include <rpc/types.h>
57 #if defined(linux) || defined(CSRG_BASED)
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"
68 implement_list_of(_Tt_string_buf)
70 typedef bool_t (*local_xdrproc_t)(XDR *, caddr_t *);
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.)
80 * content = (char *)0;
85 // The _Tt_string_buf copy constructor should not be used much, since
86 // generally pointers to _Tt_string_buf's are passed around.
90 _Tt_string_buf(const _Tt_string_buf& s)
92 content = (char *)malloc(s.length+1);
94 memcpy(content,s.content,length+1);
98 // The _Tt_string_buf destructor frees the actual string storage.
104 if (content != (char *)0) {
105 (void)free((MALLOCTYPE *)content);
109 void _Tt_string_buf::
110 set(const unsigned char *s, int len)
113 if ((s != (const unsigned char*) 0) && (len >= 0)) {
114 content = (char *)malloc(len+1);
115 memcpy(content,s,len);
122 // a non-member function for use when you have a char *, but don't
123 // yet have a _Tt_string.
125 _tt_print_escaped_string(const _Tt_ostream &os, const char *s, int length,
126 int max_print_width, int quote_it)
130 static int width_inited = 0;
131 static int _max_print_width;
132 if (! width_inited) {
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");
138 _max_print_width = atoi(s);
141 switch (max_print_width) {
142 case _Tt_string_unlimited:
143 max_print_width = 80000;
145 case _Tt_string_user_width:
146 max_print_width = _max_print_width;
159 for (count=0, i=0; count < max_print_width && i < length;) {
161 if (length - i >= MB_LEN_MAX) {
163 if ((n = mbtowc(&wc, &s[i], MB_LEN_MAX)) != -1) {
164 // multi-byte character buffer. Interpret it appropriately.
166 if (iswprint(wc) || iswspace(wc)) {
167 count += (n == 0) ? 1 : n;
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);
175 count += (3 + ((n == 0) ? 1 : n));
177 // don't print past limit, even a little.
178 if (count < max_print_width) {
179 os.sprintf(10, "\\%03C", wc);
183 i += (n == 0) ? 1 : n;
189 // non-multi-byte character buffer...
190 if (isprint((unsigned char) s[i]) ||
191 isspace((unsigned char) s[i])) {
197 // don't print past limit, even a little.
198 if (count < max_print_width) {
199 os.sprintf(10, "\\%03o", (unsigned char) s[i]);
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
219 void _Tt_string_buf::
220 print(const _Tt_ostream &os, int max_print_width, int quote_it) const
222 _tt_print_escaped_string(os, content, length, max_print_width,
226 bool_t _Tt_string_buf::
229 if (_tt_global->xdr_version() == 1) {
237 bool_t _Tt_string_buf::
243 if (xdr_int(xdrs, &length)) {
245 if (xdrs->x_op == XDR_DECODE) {
246 sp = (char *)malloc(length + 1);
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);
257 content[length] = '\0';
260 // couldn't xdr content field
266 // couldn't xdr length field
272 bool_t _Tt_string_buf::
278 if (content == (char *)0) len = -1;
280 if (xdr_int(xdrs, &len)) {
281 // if a regular string...
283 if (xdrs->x_op == XDR_DECODE) {
284 sp = (char *)malloc(len + 1);
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);
299 // couldn't xdr content field
303 // if an empty string ("")...
305 if (xdrs->x_op == XDR_DECODE) {
306 if (content != (char *)0) {
307 (void)free((MALLOCTYPE *)content);
309 content = (char *)malloc(1);
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);
327 // couldn't xdr length field
334 // The plain _Tt_string constructor creates a null string.
340 if (_tt_global != 0) {
341 *(_Tt_string_buf_ptr *)this=_tt_global->universal_null_string;
344 *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
349 // The _Tt_string copy constructor is sure to call the parent copy constructor
352 _Tt_string(const _Tt_string &s) : _Tt_string_buf_ptr(s)
357 // A _Tt_string can be constructed from a "char *" C string.
360 _Tt_string(const char *s)
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';
370 (*this)->content = (char *)0;
375 // A special constructor builds a _Tt_string containing "n" bytes,
376 // not initialized to anything.
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.
390 *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
392 (*this)->content = (char *)malloc(n+1);
393 (*this)->content[n] = '\0';
397 // A _Tt_string can be constructed from a bytestring.
400 _Tt_string(const unsigned char *s, int len)
402 *(_Tt_string_buf_ptr *)this = new _Tt_string_buf;
403 (*(_Tt_string_buf_ptr *)this)->set(s, len);
413 // Assigning from a char * string is supported, copying the string.
415 _Tt_string& _Tt_string::
416 operator=(const char * s)
418 _Tt_string newstring(s);
419 *(_Tt_string_buf_ptr *)this = newstring;
424 // "set" is very like assignment, but takes a pointer and a string
425 // to handle bytestrings.
427 _Tt_string& _Tt_string::
428 set(const unsigned char * s, int n)
430 _Tt_string newstring(s,n);
431 *(_Tt_string_buf_ptr *)this = newstring;
436 // Operator [] (subscripting) is overloaded to allow access to individual
437 // elements of the string.
439 const char& _Tt_string::
440 operator[](int offset) const
442 ASSERT(0<=offset && offset<length,"String subscript out of range");
443 return (*this)->content[offset];
447 operator[](int offset)
449 return (*this)->content[offset];
453 // operator char * (conversion to char *) returns the
457 operator char*() const
459 return (*this)->content;
463 // operator const char * (conversion to const char *) returns the
464 // base string as a const.
467 operator const char*() const
469 return (const char *) ((*this)->content);
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.
476 _Tt_string _Tt_string::
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.
486 _Tt_string _Tt_string::
489 return mid(len()-l,l);
493 // mid(o,l) returns a _Tt_string containing the l characters of the
494 // string starting at position o (zero-based.)
496 _Tt_string _Tt_string::
497 mid(int o, int l) const
499 ASSERT(o>=0 && l>=0,"Invalid argument");
504 _Tt_string result(l);
506 for (int i=0;i<l;++i) {
507 result[i] = (*this)[i+o];
512 _Tt_string _Tt_string::
513 split(int i, _Tt_string &prefix) const
520 return mid(i+1,len()-i-1);
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.
532 _Tt_string _Tt_string::
533 split(char c, _Tt_string &prefix) const
535 return split( index(c), prefix );
539 // Ditto, for string s instead of char c
541 _Tt_string _Tt_string::
542 split(const char *s, _Tt_string &prefix) const
550 return right(len()-i-strlen(s));
554 // rsplit() is like split(), but it finds the _last_ occurrence of c
556 _Tt_string _Tt_string::
557 rsplit(char c, _Tt_string &prefix) const
559 return split( rindex(c), prefix );
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
569 _Tt_string _Tt_string::
573 char *result = (char *)malloc(2*l+1); // string will get at most 2x bigger
578 for (int i=0;i<l;++i) {
583 } else if (c == '\\') {
592 r = result; // Put the value in a _Tt_string
593 (void)free((MALLOCTYPE *)result);
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.
602 _Tt_string _Tt_string::
603 unquote_nulls() const
606 unsigned char *result;
608 register unsigned char *p;
609 register unsigned char *q;
616 result = (unsigned char *)malloc(l); // string will not grow
618 p = (unsigned char *)((*this)->content);
624 ASSERT(*p,"Badly formed quote_null string");
636 r.set(result,q-result);
637 (void)free((MALLOCTYPE *)result);
642 // cat(s) returns a _Tt_string which is the concatenation of the
643 // object string and the argument string.
645 _Tt_string _Tt_string::
646 cat(const _Tt_string &s) const
648 _Tt_string result(len()+s.len());
649 int result_len = len() + s.len();
651 memcpy(result->content,(*this)->content,len());
652 memcpy(result->content+len(),s->content,s.len());
653 (result->content)[result_len] = '\0';
657 _Tt_string _Tt_string::
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';
668 _Tt_string _Tt_string::
671 return cat((long) i);
674 _Tt_string _Tt_string::
675 cat(unsigned int i) const
677 return cat((unsigned long) i);
680 _Tt_string _Tt_string::
685 sprintf(buf, "%ld", i);
689 _Tt_string _Tt_string::
690 cat(unsigned long i) const
693 sprintf(buf, "%lu", i);
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.
701 _Tt_string _Tt_string::
702 replace(const char *old, const _Tt_string &with) const
706 _Tt_string remainder = *this;
708 int oldlen = strlen(old);
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.
718 i = remainder.index(old);
720 // no more matches found
721 result = result.cat(remainder);
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);
729 } while (remainder.len() > 0);
734 // len returns the length (strlen) of the object string
739 * return (*this)->length;
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.
747 cmp(const char *q, int qlen) const
749 register char *p = (*this)->content;
750 register int plen = len();
753 if (0==p && 0==q) return 0;
759 pcmp = memcmp(p, q, (plen < qlen) ? plen : qlen);
760 if (pcmp == 0 && plen > qlen) {
762 } else if (pcmp == 0 && plen < qlen) {
769 /* XXX: old definition of cmp
772 * register char *p = (*this)->content;
773 * register char *end;
774 * register int plen = len();
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;
781 * if (qlen == -1) { // really comparing two _Tt_strings
791 * if (*p<*q) return -1;
792 * if (*p>*q) return +1;
796 * // all the chars that are there compare, so the shorter string
799 * if (plen<qlen) return -1;
800 * if (plen>qlen) return +1;
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.
818 register char *p = (*this)->content;
819 register char *end = p+len();
821 while (p<end && *p!=c) ++p;
825 return p-(*this)->content;
830 // If you really must search for null-containing strings, feel free
831 // to change this to take a const _Tt_string &.
834 index(const char *s) const
836 if (s == 0 || len() == 0) {
840 char *p = (*this)->content;
842 int slen = strlen(s);
845 while ((! found) && (p < end - slen + 1)) {
847 for (int i = 0; i < slen; i++) {
859 return p-(*this)->content;
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.
876 register char *beg = (*this)->content;
877 register char *p = beg+len()-1;
879 while (p>=beg && *p!=c) --p;
894 strchr(const char *s) const
900 strrchr(char c) const
906 hash(int max_buckets) const
910 char *p = (*this)->content;
912 while (length != 0) {
913 hash_value += (length * *p++);
916 hash_value = hash_value % max_buckets;
917 if (hash_value < 0) {
918 hash_value = 0 - hash_value;
920 return (hash_value); /* hash to a bucket number */
925 print(const _Tt_ostream &os, int max, int quote_it) const
927 (*this)->print(os, max, quote_it);
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.
936 (*this)->print(stdout);
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;
952 return((*this)->xdr(xdrs));
956 _Tt_string_list() : _Tt_string_buf_list()
961 _Tt_string_list(const _Tt_string_list &l) : _Tt_string_buf_list(l)
966 _Tt_string_list(const _Tt_string_buf_list &l) : _Tt_string_buf_list(l)
976 _Tt_string_list_ptr::
977 ~_Tt_string_list_ptr()
984 _Tt_string_list_ptr &_Tt_string_list_ptr::
985 operator=(_Tt_string_list *s)
987 *(_Tt_string_buf_list_ptr *)this = (_Tt_string_buf_list *)s;
991 _Tt_string_list_ptr &_Tt_string_list_ptr::
992 operator=(const _Tt_string_list_ptr &s)
994 return (_Tt_string_list_ptr &)_Tt_string_buf_list_ptr::operator=(s);
997 _Tt_string_list_cursor::
998 _Tt_string_list_cursor()
1002 _Tt_string_list_cursor::
1003 _Tt_string_list_cursor(const _Tt_string_list_ptr & l) : _Tt_string_buf_list_cursor(l)
1007 _Tt_string_list_cursor::
1008 ~_Tt_string_list_cursor()
1012 _Tt_string _Tt_string_list_cursor::
1015 return **(const _Tt_string_buf_list_cursor *)this;
1019 _Tt_string _Tt_string_list_cursor::
1020 operator ->() const {
1021 return **(const _Tt_string_buf_list_cursor *)this;
1025 * Encode data into an opaque Tt_string
1028 _tt_xdr_encode(xdrproc_t xdr_fn, void *data, _Tt_string &opaque_string)
1030 unsigned long datasize;
1034 if (!(datasize = _tt_xdr_sizeof(xdr_fn, (char *)data))) {
1037 _Tt_string s((int)datasize);
1038 // create an in-memory xdr stream
1039 xdrmem_create(&xdrs, (char *)s, (u_int)datasize, XDR_ENCODE);
1041 if (! (*(local_xdrproc_t)xdr_fn)(&xdrs, (caddr_t *)data)) {
1049 * Decode data from an opaque _Tt_string
1052 _tt_xdr_decode(xdrproc_t xdr_fn, void *data, _Tt_string opaque_string)
1054 char *encoded = (char *)opaque_string;
1057 xdrmem_create(&xdrs, encoded, (u_int)opaque_string.len(), XDR_DECODE);
1058 if (! (*(local_xdrproc_t)xdr_fn)(&xdrs, (caddr_t *)data)) {
1066 * XDR encode or decode a _Tt_string
1069 tt_xdr_string(XDR *xdrs, _Tt_string *s)
1071 return(s->xdr(xdrs));
1075 * XDR encode or decode a _Tt_string_list
1078 _tt_xdr_string_list(XDR *xdrs, _Tt_string_list_ptr *strings_ptr)
1080 return (*strings_ptr)->xdr(xdrs);
1083 _Tt_string_list_ptr::
1084 _Tt_string_list_ptr() : _Tt_string_buf_list_ptr()
1088 void _tt_string_print(const _Tt_ostream &os, const _Tt_object *obj)
1090 ((_Tt_string_buf *)obj)->print(os);