2005-05-11 Colin Walters <walters@verbum.org>
[platform/upstream/dbus.git] / dbus / dbus-string-util.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-string-util.c Would be in dbus-string.c, but not used in libdbus
3  * 
4  * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-string.h"
26 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
27 #include "dbus-string-private.h"
28
29 /**
30  * @addtogroup DBusString
31  * @{
32  */
33
34 /**
35  * Returns whether a string ends with the given suffix
36  *
37  * @todo memcmp might make this faster.
38  * 
39  * @param a the string
40  * @param c_str the C-style string
41  * @returns #TRUE if the string ends with the suffix
42  */
43 dbus_bool_t
44 _dbus_string_ends_with_c_str (const DBusString *a,
45                               const char       *c_str)
46 {
47   const unsigned char *ap;
48   const unsigned char *bp;
49   const unsigned char *a_end;
50   unsigned long c_str_len;
51   const DBusRealString *real_a = (const DBusRealString*) a;
52   DBUS_GENERIC_STRING_PREAMBLE (real_a);
53   _dbus_assert (c_str != NULL);
54   
55   c_str_len = strlen (c_str);
56   if (((unsigned long)real_a->len) < c_str_len)
57     return FALSE;
58   
59   ap = real_a->str + (real_a->len - c_str_len);
60   bp = (const unsigned char*) c_str;
61   a_end = real_a->str + real_a->len;
62   while (ap != a_end)
63     {
64       if (*ap != *bp)
65         return FALSE;
66       
67       ++ap;
68       ++bp;
69     }
70
71   _dbus_assert (*ap == '\0');
72   _dbus_assert (*bp == '\0');
73   
74   return TRUE;
75 }
76
77 /**
78  * Find the given byte scanning backward from the given start.
79  * Sets *found to -1 if the byte is not found.
80  *
81  * @param str the string
82  * @param start the place to start scanning (will not find the byte at this point)
83  * @param byte the byte to find
84  * @param found return location for where it was found
85  * @returns #TRUE if found
86  */
87 dbus_bool_t
88 _dbus_string_find_byte_backward (const DBusString  *str,
89                                  int                start,
90                                  unsigned char      byte,
91                                  int               *found)
92 {
93   int i;
94   DBUS_CONST_STRING_PREAMBLE (str);
95   _dbus_assert (start <= real->len);
96   _dbus_assert (start >= 0);
97   _dbus_assert (found != NULL);
98
99   i = start - 1;
100   while (i >= 0)
101     {
102       if (real->str[i] == byte)
103         break;
104       
105       --i;
106     }
107
108   if (found)
109     *found = i;
110
111   return i >= 0;
112 }
113
114 /**
115  * Skips whitespace from start, storing the first non-whitespace in *end.
116  * (whitespace is space, tab, newline, CR).
117  *
118  * @param str the string
119  * @param start where to start
120  * @param end where to store the first non-whitespace byte index
121  */
122 void
123 _dbus_string_skip_white (const DBusString *str,
124                          int               start,
125                          int              *end)
126 {
127   int i;
128   DBUS_CONST_STRING_PREAMBLE (str);
129   _dbus_assert (start <= real->len);
130   _dbus_assert (start >= 0);
131   
132   i = start;
133   while (i < real->len)
134     {
135       if (!(real->str[i] == ' ' ||
136             real->str[i] == '\n' ||
137             real->str[i] == '\r' ||
138             real->str[i] == '\t'))
139         break;
140       
141       ++i;
142     }
143
144   _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
145                                     real->str[i] == '\t'));
146   
147   if (end)
148     *end = i;
149 }
150
151 /** @} */
152
153 #ifdef DBUS_BUILD_TESTS
154 #include "dbus-test.h"
155 #include <stdio.h>
156
157 static void
158 test_max_len (DBusString *str,
159               int         max_len)
160 {
161   if (max_len > 0)
162     {
163       if (!_dbus_string_set_length (str, max_len - 1))
164         _dbus_assert_not_reached ("setting len to one less than max should have worked");
165     }
166
167   if (!_dbus_string_set_length (str, max_len))
168     _dbus_assert_not_reached ("setting len to max len should have worked");
169
170   if (_dbus_string_set_length (str, max_len + 1))
171     _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
172
173   if (!_dbus_string_set_length (str, 0))
174     _dbus_assert_not_reached ("setting len to zero should have worked");
175 }
176
177 static void
178 test_hex_roundtrip (const unsigned char *data,
179                     int                  len)
180 {
181   DBusString orig;
182   DBusString encoded;
183   DBusString decoded;
184   int end;
185
186   if (len < 0)
187     len = strlen (data);
188   
189   if (!_dbus_string_init (&orig))
190     _dbus_assert_not_reached ("could not init string");
191
192   if (!_dbus_string_init (&encoded))
193     _dbus_assert_not_reached ("could not init string");
194   
195   if (!_dbus_string_init (&decoded))
196     _dbus_assert_not_reached ("could not init string");
197
198   if (!_dbus_string_append_len (&orig, data, len))
199     _dbus_assert_not_reached ("couldn't append orig data");
200
201   if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0))
202     _dbus_assert_not_reached ("could not encode");
203
204   if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0))
205     _dbus_assert_not_reached ("could not decode");
206     
207   _dbus_assert (_dbus_string_get_length (&encoded) == end);
208
209   if (!_dbus_string_equal (&orig, &decoded))
210     {
211       const char *s;
212       
213       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
214               _dbus_string_get_length (&orig),
215               _dbus_string_get_length (&encoded),
216               _dbus_string_get_length (&decoded));
217       printf ("Original: %s\n", data);
218       s = _dbus_string_get_const_data (&decoded);
219       printf ("Decoded: %s\n", s);
220       _dbus_assert_not_reached ("original string not the same as string decoded from hex");
221     }
222   
223   _dbus_string_free (&orig);
224   _dbus_string_free (&encoded);
225   _dbus_string_free (&decoded);  
226 }
227
228 typedef void (* TestRoundtripFunc) (const unsigned char *data,
229                                     int                  len);
230 static void
231 test_roundtrips (TestRoundtripFunc func)
232 {
233   (* func) ("Hello this is a string\n", -1);
234   (* func) ("Hello this is a string\n1", -1);
235   (* func) ("Hello this is a string\n12", -1);
236   (* func) ("Hello this is a string\n123", -1);
237   (* func) ("Hello this is a string\n1234", -1);
238   (* func) ("Hello this is a string\n12345", -1);
239   (* func) ("", 0);
240   (* func) ("1", 1);
241   (* func) ("12", 2);
242   (* func) ("123", 3);
243   (* func) ("1234", 4);
244   (* func) ("12345", 5);
245   (* func) ("", 1);
246   (* func) ("1", 2);
247   (* func) ("12", 3);
248   (* func) ("123", 4);
249   (* func) ("1234", 5);
250   (* func) ("12345", 6);
251   {
252     unsigned char buf[512];
253     int i;
254     
255     i = 0;
256     while (i < _DBUS_N_ELEMENTS (buf))
257       {
258         buf[i] = i;
259         ++i;
260       }
261     i = 0;
262     while (i < _DBUS_N_ELEMENTS (buf))
263       {
264         (* func) (buf, i);
265         ++i;
266       }
267   }
268 }
269
270 #ifdef DBUS_BUILD_TESTS
271 /* The max length thing is sort of a historical artifact
272  * from a feature that turned out to be dumb; perhaps
273  * we should purge it entirely. The problem with
274  * the feature is that it looks like memory allocation
275  * failure, but is not a transient or resolvable failure.
276  */
277 static void
278 set_max_length (DBusString *str,
279                 int         max_length)
280 {
281   DBusRealString *real;
282   
283   real = (DBusRealString*) str;
284
285   real->max_length = max_length;
286 }
287 #endif /* DBUS_BUILD_TESTS */
288
289 /**
290  * @ingroup DBusStringInternals
291  * Unit test for DBusString.
292  *
293  * @todo Need to write tests for _dbus_string_copy() and
294  * _dbus_string_move() moving to/from each of start/middle/end of a
295  * string. Also need tests for _dbus_string_move_len ()
296  * 
297  * @returns #TRUE on success.
298  */
299 dbus_bool_t
300 _dbus_string_test (void)
301 {
302   DBusString str;
303   DBusString other;
304   int i, end;
305   long v;
306   double d;
307   int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
308   char *s;
309   dbus_unichar_t ch;
310   
311   i = 0;
312   while (i < _DBUS_N_ELEMENTS (lens))
313     {
314       if (!_dbus_string_init (&str))
315         _dbus_assert_not_reached ("failed to init string");
316
317       set_max_length (&str, lens[i]);
318       
319       test_max_len (&str, lens[i]);
320       _dbus_string_free (&str);
321
322       ++i;
323     }
324
325   /* Test shortening and setting length */
326   i = 0;
327   while (i < _DBUS_N_ELEMENTS (lens))
328     {
329       int j;
330       
331       if (!_dbus_string_init (&str))
332         _dbus_assert_not_reached ("failed to init string");
333
334       set_max_length (&str, lens[i]);
335       
336       if (!_dbus_string_set_length (&str, lens[i]))
337         _dbus_assert_not_reached ("failed to set string length");
338
339       j = lens[i];
340       while (j > 0)
341         {
342           _dbus_assert (_dbus_string_get_length (&str) == j);
343           if (j > 0)
344             {
345               _dbus_string_shorten (&str, 1);
346               _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
347             }
348           --j;
349         }
350       
351       _dbus_string_free (&str);
352
353       ++i;
354     }
355
356   /* Test equality */
357   if (!_dbus_string_init (&str))
358     _dbus_assert_not_reached ("oom");
359
360   if (!_dbus_string_append (&str, "Hello World"))
361     _dbus_assert_not_reached ("oom");
362
363   _dbus_string_init_const (&other, "H");
364   _dbus_assert (_dbus_string_equal_substring (&str, 0, 1, &other, 0));
365   _dbus_assert (_dbus_string_equal_substring (&str, 1, 0, &other, 1));
366   _dbus_string_init_const (&other, "Hello");
367   _dbus_assert (_dbus_string_equal_substring (&str, 0, 5, &other, 0));
368   _dbus_assert (_dbus_string_equal_substring (&str, 1, 4, &other, 1));
369   _dbus_assert (_dbus_string_equal_substring (&str, 2, 3, &other, 2));
370   _dbus_assert (_dbus_string_equal_substring (&str, 3, 2, &other, 3));
371   _dbus_assert (_dbus_string_equal_substring (&str, 4, 1, &other, 4));
372   _dbus_assert (_dbus_string_equal_substring (&str, 5, 0, &other, 5));
373
374   _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 0));
375   _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 1));
376   _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 2));
377   _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 3));
378   _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 4));
379   _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 5));
380
381   
382   _dbus_string_init_const (&other, "World");
383   _dbus_assert (_dbus_string_equal_substring (&str, 6,  5, &other, 0));
384   _dbus_assert (_dbus_string_equal_substring (&str, 7,  4, &other, 1));
385   _dbus_assert (_dbus_string_equal_substring (&str, 8,  3, &other, 2));
386   _dbus_assert (_dbus_string_equal_substring (&str, 9,  2, &other, 3));
387   _dbus_assert (_dbus_string_equal_substring (&str, 10, 1, &other, 4));
388   _dbus_assert (_dbus_string_equal_substring (&str, 11, 0, &other, 5));
389
390   _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 6));
391   _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 7));
392   _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 8));
393   _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 9));
394   _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 10));
395   _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 11));
396   
397   _dbus_string_free (&str);
398   
399   /* Test appending data */
400   if (!_dbus_string_init (&str))
401     _dbus_assert_not_reached ("failed to init string");
402
403   i = 0;
404   while (i < 10)
405     {
406       if (!_dbus_string_append (&str, "a"))
407         _dbus_assert_not_reached ("failed to append string to string\n");
408
409       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
410
411       if (!_dbus_string_append_byte (&str, 'b'))
412         _dbus_assert_not_reached ("failed to append byte to string\n");
413
414       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
415                     
416       ++i;
417     }
418
419   _dbus_string_free (&str);
420
421   /* Check steal_data */
422   
423   if (!_dbus_string_init (&str))
424     _dbus_assert_not_reached ("failed to init string");
425
426   if (!_dbus_string_append (&str, "Hello World"))
427     _dbus_assert_not_reached ("could not append to string");
428
429   i = _dbus_string_get_length (&str);
430   
431   if (!_dbus_string_steal_data (&str, &s))
432     _dbus_assert_not_reached ("failed to steal data");
433
434   _dbus_assert (_dbus_string_get_length (&str) == 0);
435   _dbus_assert (((int)strlen (s)) == i);
436
437   dbus_free (s);
438
439   /* Check move */
440   
441   if (!_dbus_string_append (&str, "Hello World"))
442     _dbus_assert_not_reached ("could not append to string");
443
444   i = _dbus_string_get_length (&str);
445
446   if (!_dbus_string_init (&other))
447     _dbus_assert_not_reached ("could not init string");
448   
449   if (!_dbus_string_move (&str, 0, &other, 0))
450     _dbus_assert_not_reached ("could not move");
451
452   _dbus_assert (_dbus_string_get_length (&str) == 0);
453   _dbus_assert (_dbus_string_get_length (&other) == i);
454
455   if (!_dbus_string_append (&str, "Hello World"))
456     _dbus_assert_not_reached ("could not append to string");
457   
458   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
459     _dbus_assert_not_reached ("could not move");
460
461   _dbus_assert (_dbus_string_get_length (&str) == 0);
462   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
463
464     if (!_dbus_string_append (&str, "Hello World"))
465     _dbus_assert_not_reached ("could not append to string");
466   
467   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
468     _dbus_assert_not_reached ("could not move");
469
470   _dbus_assert (_dbus_string_get_length (&str) == 0);
471   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
472   
473   _dbus_string_free (&other);
474
475   /* Check copy */
476   
477   if (!_dbus_string_append (&str, "Hello World"))
478     _dbus_assert_not_reached ("could not append to string");
479
480   i = _dbus_string_get_length (&str);
481   
482   if (!_dbus_string_init (&other))
483     _dbus_assert_not_reached ("could not init string");
484   
485   if (!_dbus_string_copy (&str, 0, &other, 0))
486     _dbus_assert_not_reached ("could not copy");
487
488   _dbus_assert (_dbus_string_get_length (&str) == i);
489   _dbus_assert (_dbus_string_get_length (&other) == i);
490
491   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
492     _dbus_assert_not_reached ("could not copy");
493
494   _dbus_assert (_dbus_string_get_length (&str) == i);
495   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
496   _dbus_assert (_dbus_string_equal_c_str (&other,
497                                           "Hello WorldHello World"));
498
499   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
500     _dbus_assert_not_reached ("could not copy");
501
502   _dbus_assert (_dbus_string_get_length (&str) == i);
503   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
504   _dbus_assert (_dbus_string_equal_c_str (&other,
505                                           "Hello WorldHello WorldHello World"));
506   
507   _dbus_string_free (&str);
508   _dbus_string_free (&other);
509
510   /* Check replace */
511
512   if (!_dbus_string_init (&str))
513     _dbus_assert_not_reached ("failed to init string");
514   
515   if (!_dbus_string_append (&str, "Hello World"))
516     _dbus_assert_not_reached ("could not append to string");
517
518   i = _dbus_string_get_length (&str);
519   
520   if (!_dbus_string_init (&other))
521     _dbus_assert_not_reached ("could not init string");
522   
523   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
524                                  &other, 0, _dbus_string_get_length (&other)))
525     _dbus_assert_not_reached ("could not replace");
526
527   _dbus_assert (_dbus_string_get_length (&str) == i);
528   _dbus_assert (_dbus_string_get_length (&other) == i);
529   _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
530   
531   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
532                                  &other, 5, 1))
533     _dbus_assert_not_reached ("could not replace center space");
534
535   _dbus_assert (_dbus_string_get_length (&str) == i);
536   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
537   _dbus_assert (_dbus_string_equal_c_str (&other,
538                                           "HelloHello WorldWorld"));
539
540   
541   if (!_dbus_string_replace_len (&str, 1, 1,
542                                  &other,
543                                  _dbus_string_get_length (&other) - 1,
544                                  1))
545     _dbus_assert_not_reached ("could not replace end character");
546   
547   _dbus_assert (_dbus_string_get_length (&str) == i);
548   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
549   _dbus_assert (_dbus_string_equal_c_str (&other,
550                                           "HelloHello WorldWorle"));
551   
552   _dbus_string_free (&str);
553   _dbus_string_free (&other);
554   
555   /* Check append/get unichar */
556   
557   if (!_dbus_string_init (&str))
558     _dbus_assert_not_reached ("failed to init string");
559
560   ch = 0;
561   if (!_dbus_string_append_unichar (&str, 0xfffc))
562     _dbus_assert_not_reached ("failed to append unichar");
563
564   _dbus_string_get_unichar (&str, 0, &ch, &i);
565
566   _dbus_assert (ch == 0xfffc);
567   _dbus_assert (i == _dbus_string_get_length (&str));
568
569   _dbus_string_free (&str);
570
571   /* Check insert/set/get byte */
572   
573   if (!_dbus_string_init (&str))
574     _dbus_assert_not_reached ("failed to init string");
575
576   if (!_dbus_string_append (&str, "Hello"))
577     _dbus_assert_not_reached ("failed to append Hello");
578
579   _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
580   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
581   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
582   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
583   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
584
585   _dbus_string_set_byte (&str, 1, 'q');
586   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
587
588   if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
589     _dbus_assert_not_reached ("can't insert byte");
590
591   if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
592     _dbus_assert_not_reached ("can't insert byte");
593
594   if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
595     _dbus_assert_not_reached ("can't insert byte");
596   
597   _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
598   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
599   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
600   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
601   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
602   _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
603   _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
604   _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
605   _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
606   _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
607   _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');
608
609   _dbus_string_free (&str);
610   
611   /* Check append/parse int/double */
612   
613   if (!_dbus_string_init (&str))
614     _dbus_assert_not_reached ("failed to init string");
615
616   if (!_dbus_string_append_int (&str, 27))
617     _dbus_assert_not_reached ("failed to append int");
618
619   i = _dbus_string_get_length (&str);
620
621   if (!_dbus_string_parse_int (&str, 0, &v, &end))
622     _dbus_assert_not_reached ("failed to parse int");
623
624   _dbus_assert (v == 27);
625   _dbus_assert (end == i);
626
627   _dbus_string_free (&str);
628   
629   if (!_dbus_string_init (&str))
630     _dbus_assert_not_reached ("failed to init string");
631   
632   if (!_dbus_string_append_double (&str, 50.3))
633     _dbus_assert_not_reached ("failed to append float");
634
635   i = _dbus_string_get_length (&str);
636
637   if (!_dbus_string_parse_double (&str, 0, &d, &end))
638     _dbus_assert_not_reached ("failed to parse float");
639
640   _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
641   _dbus_assert (end == i);
642
643   _dbus_string_free (&str);
644
645   /* Test find */
646   if (!_dbus_string_init (&str))
647     _dbus_assert_not_reached ("failed to init string");
648
649   if (!_dbus_string_append (&str, "Hello"))
650     _dbus_assert_not_reached ("couldn't append to string");
651   
652   if (!_dbus_string_find (&str, 0, "He", &i))
653     _dbus_assert_not_reached ("didn't find 'He'");
654   _dbus_assert (i == 0);
655
656   if (!_dbus_string_find (&str, 0, "Hello", &i))
657     _dbus_assert_not_reached ("didn't find 'Hello'");
658   _dbus_assert (i == 0);
659   
660   if (!_dbus_string_find (&str, 0, "ello", &i))
661     _dbus_assert_not_reached ("didn't find 'ello'");
662   _dbus_assert (i == 1);
663
664   if (!_dbus_string_find (&str, 0, "lo", &i))
665     _dbus_assert_not_reached ("didn't find 'lo'");
666   _dbus_assert (i == 3);
667
668   if (!_dbus_string_find (&str, 2, "lo", &i))
669     _dbus_assert_not_reached ("didn't find 'lo'");
670   _dbus_assert (i == 3);
671
672   if (_dbus_string_find (&str, 4, "lo", &i))
673     _dbus_assert_not_reached ("did find 'lo'");
674   
675   if (!_dbus_string_find (&str, 0, "l", &i))
676     _dbus_assert_not_reached ("didn't find 'l'");
677   _dbus_assert (i == 2);
678
679   if (!_dbus_string_find (&str, 0, "H", &i))
680     _dbus_assert_not_reached ("didn't find 'H'");
681   _dbus_assert (i == 0);
682
683   if (!_dbus_string_find (&str, 0, "", &i))
684     _dbus_assert_not_reached ("didn't find ''");
685   _dbus_assert (i == 0);
686   
687   if (_dbus_string_find (&str, 0, "Hello!", NULL))
688     _dbus_assert_not_reached ("Did find 'Hello!'");
689
690   if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
691     _dbus_assert_not_reached ("Did find 'Oh, Hello'");
692   
693   if (_dbus_string_find (&str, 0, "ill", NULL))
694     _dbus_assert_not_reached ("Did find 'ill'");
695
696   if (_dbus_string_find (&str, 0, "q", NULL))
697     _dbus_assert_not_reached ("Did find 'q'");
698
699   if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
700     _dbus_assert_not_reached ("Didn't find 'He'");
701
702   if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
703     _dbus_assert_not_reached ("Did find 'Hello'");
704
705   if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i))
706     _dbus_assert_not_reached ("Did not find 'H'");
707   _dbus_assert (i == 0);
708
709   if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i))
710     _dbus_assert_not_reached ("Did not find 'o'");
711   _dbus_assert (i == _dbus_string_get_length (&str) - 1);
712
713   if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i))
714     _dbus_assert_not_reached ("Did find 'o'");
715   _dbus_assert (i == -1);
716
717   if (_dbus_string_find_byte_backward (&str, 1, 'e', &i))
718     _dbus_assert_not_reached ("Did find 'e'");
719   _dbus_assert (i == -1);
720
721   if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i))
722     _dbus_assert_not_reached ("Didn't find 'e'");
723   _dbus_assert (i == 1);
724   
725   _dbus_string_free (&str);
726
727   /* Hex encoding */
728   _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string");
729   if (!_dbus_string_init (&other))
730     _dbus_assert_not_reached ("could not init string");
731
732   if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0))
733     _dbus_assert_not_reached ("deccoded bogus hex string with no error");
734
735   _dbus_assert (end == 8);
736
737   _dbus_string_free (&other);
738
739   test_roundtrips (test_hex_roundtrip);
740   
741   _dbus_string_free (&str);
742   
743   return TRUE;
744 }
745
746 #endif /* DBUS_BUILD_TESTS */