string.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* string.c - common string syntax routines */
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #include "syntax.h"
  46. #if defined(IRIX)
  47. #include <unistd.h>
  48. #endif
  49. static int string_filter_approx( struct berval *bvfilter,
  50. Slapi_Value **bvals, Slapi_Value **retVal );
  51. static void substring_comp_keys( Slapi_Value ***ivals, int *nsubs, char *str,
  52. int prepost, int syntax );
  53. int
  54. string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax,
  55. int ftype, Slapi_Value **retVal )
  56. {
  57. int i, rc;
  58. struct berval bvfilter_norm;
  59. if(retVal) {
  60. *retVal = NULL;
  61. }
  62. if ( ftype == LDAP_FILTER_APPROX ) {
  63. return( string_filter_approx( bvfilter, bvals, retVal ) );
  64. }
  65. bvfilter_norm.bv_val = slapi_ch_malloc( bvfilter->bv_len + 1 );
  66. SAFEMEMCPY( bvfilter_norm.bv_val, bvfilter->bv_val, bvfilter->bv_len );
  67. bvfilter_norm.bv_val[bvfilter->bv_len] = '\0';
  68. value_normalize( bvfilter_norm.bv_val, syntax, 1 /* trim leading blanks */ );
  69. bvfilter_norm.bv_len = strlen(bvfilter_norm.bv_val);
  70. for ( i = 0; bvals[i] != NULL; i++ ) {
  71. rc = value_cmp( (struct berval*)slapi_value_get_berval(bvals[i]), &bvfilter_norm, syntax, 1/* Normalise the first value only */ );
  72. switch ( ftype ) {
  73. case LDAP_FILTER_GE:
  74. if ( rc >= 0 ) {
  75. if(retVal) {
  76. *retVal = bvals[i];
  77. }
  78. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  79. return( 0 );
  80. }
  81. break;
  82. case LDAP_FILTER_LE:
  83. if ( rc <= 0 ) {
  84. if(retVal) {
  85. *retVal = bvals[i];
  86. }
  87. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  88. return( 0 );
  89. }
  90. break;
  91. case LDAP_FILTER_EQUALITY:
  92. if ( rc == 0 ) {
  93. if(retVal) {
  94. *retVal = bvals[i];
  95. }
  96. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  97. return( 0 );
  98. }
  99. break;
  100. }
  101. }
  102. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  103. return( -1 );
  104. }
  105. static int
  106. string_filter_approx( struct berval *bvfilter, Slapi_Value **bvals,
  107. Slapi_Value **retVal)
  108. {
  109. int i, rc;
  110. int ava_wordcount;
  111. char *w1, *w2, *c1, *c2;
  112. /*
  113. * try to match words in each filter value in order
  114. * in the attribute value.
  115. * XXX should do this once for the filter and save it XXX
  116. */
  117. rc = -1;
  118. if(retVal) {
  119. *retVal = NULL;
  120. }
  121. for ( i = 0; bvals[i] != NULL; i++ ) {
  122. w2 = (char*)slapi_value_get_string(bvals[i]); /* JCM cast */
  123. ava_wordcount = 0;
  124. /* for each word in the filter value */
  125. for ( w1 = first_word( bvfilter->bv_val ); w1 != NULL;
  126. w1 = next_word( w1 ) ) {
  127. ++ava_wordcount;
  128. if ( (c1 = phonetic( w1 )) == NULL ) {
  129. break;
  130. }
  131. /*
  132. * for each word in the attribute value from
  133. * where we left off...
  134. */
  135. for ( w2 = first_word( w2 ); w2 != NULL;
  136. w2 = next_word( w2 ) ) {
  137. c2 = phonetic( w2 );
  138. rc = strcmp( c1, c2 );
  139. slapi_ch_free((void**)&c2 );
  140. if ( rc == 0 ) {
  141. if(retVal) {
  142. *retVal = bvals[i];
  143. }
  144. break;
  145. }
  146. }
  147. slapi_ch_free((void**)&c1 );
  148. /*
  149. * if we stopped because we ran out of words
  150. * before making a match, go on to the next
  151. * value. otherwise try to keep matching
  152. * words in this value from where we left off.
  153. */
  154. if ( w2 == NULL ) {
  155. break;
  156. } else {
  157. w2 = next_word( w2 );
  158. }
  159. }
  160. /*
  161. * if we stopped because we ran out of words and
  162. * we found at leasy one word, we have a match.
  163. */
  164. if ( w1 == NULL && ava_wordcount > 0 ) {
  165. rc = 0;
  166. break;
  167. }
  168. }
  169. LDAPDebug( LDAP_DEBUG_TRACE, "<= string_filter_approx %d\n",
  170. rc, 0, 0 );
  171. return( rc );
  172. }
  173. int
  174. string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
  175. Slapi_Value **bvals, int syntax )
  176. {
  177. int i, j, rc, size=0;
  178. char *p, *end, *realval, *tmpbuf, *bigpat = NULL;
  179. size_t tmpbufsize;
  180. char pat[BUFSIZ];
  181. char buf[BUFSIZ];
  182. char ebuf[BUFSIZ];
  183. time_t curtime = 0;
  184. time_t time_up = 0;
  185. time_t optime = 0; /* time op was initiated */
  186. int timelimit = 0; /* search timelimit */
  187. LDAPDebug( LDAP_DEBUG_FILTER, "=> string_filter_sub\n",
  188. 0, 0, 0 );
  189. slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
  190. slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
  191. /*
  192. * (timelimit==-1) means no time limit
  193. */
  194. time_up = ( timelimit==-1 ? -1 : optime + timelimit);
  195. /*
  196. * construct a regular expression corresponding to the
  197. * filter and let regex do the work for each value
  198. * XXX should do this once and save it somewhere XXX
  199. */
  200. pat[0] = '\0';
  201. p = pat;
  202. end = pat + sizeof(pat) - 2; /* leave room for null */
  203. if ( initial != NULL ) {
  204. size = strlen( initial ) + 1; /* add 1 for "^" */
  205. }
  206. if ( any != NULL ) {
  207. i = 0;
  208. while ( any[i] ) {
  209. size += strlen(any[i++]) + 2; /* add 2 for ".*" */
  210. }
  211. }
  212. if ( final != NULL ) {
  213. size += strlen( final ) + 3; /* add 3 for ".*" and "$" */
  214. }
  215. size *= 2; /* doubled in case all filter chars need escaping */
  216. size++; /* add 1 for null */
  217. if ( p + size > end ) {
  218. bigpat = slapi_ch_malloc( size );
  219. p = bigpat;
  220. }
  221. if ( initial != NULL ) {
  222. value_normalize( initial, syntax, 1 /* trim leading blanks */ );
  223. *p++ = '^';
  224. filter_strcpy_special( p, initial );
  225. p = strchr( p, '\0' );
  226. }
  227. if ( any != NULL ) {
  228. for ( i = 0; any[i] != NULL; i++ ) {
  229. value_normalize( any[i], syntax, 0 /* DO NOT trim leading blanks */ );
  230. /* ".*" + value */
  231. *p++ = '.';
  232. *p++ = '*';
  233. filter_strcpy_special( p, any[i] );
  234. p = strchr( p, '\0' );
  235. }
  236. }
  237. if ( final != NULL ) {
  238. value_normalize( final, syntax, 0 /* DO NOT trim leading blanks */ );
  239. /* ".*" + value */
  240. *p++ = '.';
  241. *p++ = '*';
  242. filter_strcpy_special( p, final );
  243. strcat( p, "$" );
  244. }
  245. /* compile the regex */
  246. p = (bigpat) ? bigpat : pat;
  247. slapd_re_lock();
  248. if ( (tmpbuf = slapd_re_comp( p )) != 0 ) {
  249. LDAPDebug( LDAP_DEBUG_ANY, "re_comp (%s) failed (%s): %s\n",
  250. pat, p, tmpbuf );
  251. rc = LDAP_OPERATIONS_ERROR;
  252. goto bailout;
  253. } else {
  254. LDAPDebug( LDAP_DEBUG_TRACE, "re_comp (%s)\n",
  255. escape_string( p, ebuf ), 0, 0 );
  256. }
  257. curtime = current_time();
  258. if ( time_up != -1 && curtime > time_up ) {
  259. rc = LDAP_TIMELIMIT_EXCEEDED;
  260. goto bailout;
  261. }
  262. /*
  263. * test the regex against each value
  264. */
  265. rc = -1;
  266. tmpbuf = NULL;
  267. tmpbufsize = 0;
  268. for ( j = 0; bvals[j] != NULL; j++ ) {
  269. int tmprc;
  270. size_t len;
  271. const struct berval *bvp = slapi_value_get_berval(bvals[j]);
  272. len = bvp->bv_len;
  273. if ( len < sizeof(buf) ) {
  274. strcpy( buf, bvp->bv_val );
  275. realval = buf;
  276. } else if ( len < tmpbufsize ) {
  277. strcpy( buf, bvp->bv_val );
  278. realval = tmpbuf;
  279. } else {
  280. tmpbuf = (char *) slapi_ch_realloc( tmpbuf, len + 1 );
  281. strcpy( tmpbuf, bvp->bv_val );
  282. realval = tmpbuf;
  283. }
  284. value_normalize( realval, syntax, 1 /* trim leading blanks */ );
  285. tmprc = slapd_re_exec( realval, time_up );
  286. LDAPDebug( LDAP_DEBUG_TRACE, "re_exec (%s) %i\n",
  287. escape_string( realval, ebuf ), tmprc, 0 );
  288. if ( tmprc == 1 ) {
  289. rc = 0;
  290. break;
  291. } else if ( tmprc != 0 ) {
  292. rc = tmprc;
  293. break;
  294. }
  295. }
  296. bailout:
  297. slapd_re_unlock();
  298. slapi_ch_free((void**)&tmpbuf ); /* NULL is fine */
  299. slapi_ch_free((void**)&bigpat ); /* NULL is fine */
  300. LDAPDebug( LDAP_DEBUG_FILTER, "<= string_filter_sub %d\n",
  301. rc, 0, 0 );
  302. return( rc );
  303. }
  304. int
  305. string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,
  306. Slapi_Value ***ivals, int syntax, int ftype )
  307. {
  308. int nsubs, numbvals = 0, n;
  309. Slapi_Value **nbvals, **nbvlp;
  310. Slapi_Value **bvlp;
  311. char *w, *c, *p;
  312. switch ( ftype ) {
  313. case LDAP_FILTER_EQUALITY:
  314. /* allocate a new array for the normalized values */
  315. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  316. numbvals++;
  317. }
  318. nbvals = (Slapi_Value **) slapi_ch_calloc( (numbvals + 1), sizeof(Slapi_Value *));
  319. for ( bvlp = bvals, nbvlp = nbvals; bvlp && *bvlp; bvlp++, nbvlp++ )
  320. {
  321. c = slapi_ch_strdup(slapi_value_get_string(*bvlp));
  322. /* if the NORMALIZED flag is set, skip normalizing */
  323. if (!(slapi_value_get_flags(*bvlp) & SLAPI_ATTR_FLAG_NORMALIZED))
  324. value_normalize( c, syntax, 1 /* trim leading blanks */ );
  325. *nbvlp = slapi_value_new_string_passin(c);
  326. }
  327. *ivals = nbvals;
  328. break;
  329. case LDAP_FILTER_APPROX:
  330. /* XXX should not do this twice! XXX */
  331. /* get an upper bound on the number of ivals */
  332. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  333. for ( w = first_word( (char*)slapi_value_get_string(*bvlp) );
  334. w != NULL; w = next_word( w ) ) {
  335. numbvals++;
  336. }
  337. }
  338. nbvals = (Slapi_Value **) slapi_ch_calloc( (numbvals + 1), sizeof(Slapi_Value *) );
  339. n = 0;
  340. nbvlp = nbvals;
  341. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  342. for ( w = first_word( (char*)slapi_value_get_string(*bvlp) );
  343. w != NULL; w = next_word( w ) ) {
  344. if ( (c = phonetic( w )) != NULL ) {
  345. *nbvlp = slapi_value_new_string_passin(c);
  346. nbvlp++;
  347. }
  348. }
  349. }
  350. /* even if (n == 0), we should return the array nbvals w/ NULL items */
  351. *ivals = nbvals;
  352. break;
  353. case LDAP_FILTER_SUBSTRINGS:
  354. {
  355. /* XXX should remove duplicates! XXX */
  356. Slapi_Value *bvdup;
  357. const struct berval *bvp;
  358. char buf[SUBLEN+1];
  359. int i;
  360. nsubs = 0;
  361. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  362. /*
  363. * Note: this calculation may err on the high side,
  364. * because value_normalize(), which is called below
  365. * before we actually create the substring keys, may
  366. * reduce the length of the value in some cases. For
  367. * example, spaces are removed when space insensitive
  368. * strings are normalized. But it's okay for nsubs to
  369. * be too big. Since the ivals array is NULL terminated,
  370. * the only downside is that we allocate more space than
  371. * we really need.
  372. */
  373. nsubs += slapi_value_get_length(*bvlp) - SUBLEN + 3;
  374. }
  375. *ivals = (Slapi_Value **) slapi_ch_calloc( (nsubs + 1), sizeof(Slapi_Value *) );
  376. buf[SUBLEN] = '\0';
  377. n = 0;
  378. bvdup= slapi_value_new();
  379. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  380. c = slapi_ch_strdup(slapi_value_get_string(*bvlp));
  381. value_normalize( c, syntax, 1 /* trim leading blanks */ );
  382. slapi_value_set_string_passin(bvdup, c);
  383. bvp = slapi_value_get_berval(bvdup);
  384. /* leading */
  385. if ( bvp->bv_len > SUBLEN - 2 ) {
  386. buf[0] = '^';
  387. for ( i = 0; i < SUBLEN - 1; i++ ) {
  388. buf[i + 1] = bvp->bv_val[i];
  389. }
  390. (*ivals)[n] = slapi_value_new_string(buf);
  391. n++;
  392. }
  393. /* any */
  394. for ( p = bvp->bv_val;
  395. p < (bvp->bv_val + bvp->bv_len - SUBLEN + 1);
  396. p++ ) {
  397. for ( i = 0; i < SUBLEN; i++ ) {
  398. buf[i] = p[i];
  399. }
  400. buf[SUBLEN] = '\0';
  401. (*ivals)[n] = slapi_value_new_string(buf);
  402. n++;
  403. }
  404. /* trailing */
  405. if ( bvp->bv_len > SUBLEN - 2 ) {
  406. p = bvp->bv_val + bvp->bv_len - SUBLEN + 1;
  407. for ( i = 0; i < SUBLEN - 1; i++ ) {
  408. buf[i] = p[i];
  409. }
  410. buf[SUBLEN - 1] = '$';
  411. (*ivals)[n] = slapi_value_new_string(buf);
  412. n++;
  413. }
  414. }
  415. slapi_value_free(&bvdup);
  416. }
  417. break;
  418. }
  419. return( 0 );
  420. }
  421. /* we've added code to make our equality filter processing faster */
  422. int
  423. string_assertion2keys_ava(
  424. Slapi_PBlock *pb,
  425. Slapi_Value *val,
  426. Slapi_Value ***ivals,
  427. int syntax,
  428. int ftype
  429. )
  430. {
  431. int i, numbvals;
  432. size_t len;
  433. char *w, *c;
  434. Slapi_Value *tmpval=NULL;
  435. switch ( ftype ) {
  436. case LDAP_FILTER_EQUALITY_FAST:
  437. /* this code is trying to avoid multiple malloc/frees */
  438. len=slapi_value_get_length(val);
  439. tmpval=(*ivals)[0];
  440. if (len >= tmpval->bv.bv_len) {
  441. tmpval->bv.bv_val=(char *)slapi_ch_malloc(len+1);
  442. }
  443. memcpy(tmpval->bv.bv_val,slapi_value_get_string(val),len);
  444. tmpval->bv.bv_val[len]='\0';
  445. value_normalize(tmpval->bv.bv_val, syntax, 1 /* trim leading blanks */ );
  446. tmpval->bv.bv_len=strlen(tmpval->bv.bv_val);
  447. break;
  448. case LDAP_FILTER_EQUALITY:
  449. (*ivals) = (Slapi_Value **) slapi_ch_malloc( 2 * sizeof(Slapi_Value *) );
  450. (*ivals)[0] = slapi_value_dup( val );
  451. value_normalize( (*ivals)[0]->bv.bv_val, syntax, 1 /* trim leading blanks */ );
  452. (*ivals)[0]->bv.bv_len = strlen( (*ivals)[0]->bv.bv_val );
  453. (*ivals)[1] = NULL;
  454. break;
  455. case LDAP_FILTER_APPROX:
  456. /* XXX should not do this twice! XXX */
  457. /* get an upper bound on the number of ivals */
  458. numbvals = 0;
  459. for ( w = first_word( (char*)slapi_value_get_string(val) ); w != NULL;
  460. w = next_word( w ) ) {
  461. numbvals++;
  462. }
  463. (*ivals) = (Slapi_Value **) slapi_ch_malloc( (numbvals + 1) *
  464. sizeof(Slapi_Value *) );
  465. i = 0;
  466. for ( w = first_word( (char*)slapi_value_get_string(val) ); w != NULL;
  467. w = next_word( w ) ) {
  468. if ( (c = phonetic( w )) != NULL ) {
  469. (*ivals)[i] = slapi_value_new_string_passin(c);
  470. i++;
  471. }
  472. }
  473. (*ivals)[i] = NULL;
  474. if ( i == 0 ) {
  475. slapi_ch_free((void**)ivals );
  476. return( 0 );
  477. }
  478. break;
  479. default:
  480. LDAPDebug( LDAP_DEBUG_ANY,
  481. "string_assertion2keys_ava: unknown ftype 0x%x\n",
  482. ftype, 0, 0 );
  483. break;
  484. }
  485. return( 0 );
  486. }
  487. int
  488. string_assertion2keys_sub(
  489. Slapi_PBlock *pb,
  490. char *initial,
  491. char **any,
  492. char *final,
  493. Slapi_Value ***ivals,
  494. int syntax
  495. )
  496. {
  497. int nsubs, i, len;
  498. *ivals = NULL;
  499. /*
  500. * First figure out how many keys we will return. The answer is based
  501. * on the length of each assertion value. Since normalization may
  502. * reduce the length (such as when spaces are removed from space
  503. * insensitive strings), we call value_normalize() before checking
  504. * the length.
  505. */
  506. nsubs = 0;
  507. if ( initial != NULL ) {
  508. value_normalize( initial, syntax, 0 /* do not trim leading blanks */ );
  509. if ( strlen( initial ) > SUBLEN - 2 ) {
  510. nsubs += strlen( initial ) - SUBLEN + 2;
  511. } else {
  512. initial = NULL; /* save some work later */
  513. }
  514. }
  515. for ( i = 0; any != NULL && any[i] != NULL; i++ ) {
  516. value_normalize( any[i], syntax, 0 /* do not trim leading blanks */ );
  517. len = strlen( any[i] );
  518. if ( len >= SUBLEN ) {
  519. nsubs += len - SUBLEN + 1;
  520. }
  521. }
  522. if ( final != NULL ) {
  523. value_normalize( final, syntax, 0 /* do not trim leading blanks */ );
  524. if ( strlen( final ) > SUBLEN - 2 ) {
  525. nsubs += strlen( final ) - SUBLEN + 2;
  526. } else {
  527. final = NULL; /* save some work later */
  528. }
  529. }
  530. if ( nsubs == 0 ) { /* no keys to return */
  531. return( 0 );
  532. }
  533. /*
  534. * Next, allocated the ivals array and fill it in with the actual
  535. * keys. *ivals is a NULL terminated array of Slapi_Value pointers.
  536. */
  537. *ivals = (Slapi_Value **) slapi_ch_malloc( (nsubs + 1) * sizeof(Slapi_Value *) );
  538. nsubs = 0;
  539. if ( initial != NULL ) {
  540. substring_comp_keys( ivals, &nsubs, initial, '^', syntax );
  541. }
  542. for ( i = 0; any != NULL && any[i] != NULL; i++ ) {
  543. if ( strlen( any[i] ) < SUBLEN ) {
  544. continue;
  545. }
  546. substring_comp_keys( ivals, &nsubs, any[i], 0, syntax );
  547. }
  548. if ( final != NULL ) {
  549. substring_comp_keys( ivals, &nsubs, final, '$', syntax );
  550. }
  551. (*ivals)[nsubs] = NULL;
  552. return( 0 );
  553. }
  554. static void
  555. substring_comp_keys(
  556. Slapi_Value ***ivals,
  557. int *nsubs,
  558. char *str,
  559. int prepost,
  560. int syntax
  561. )
  562. {
  563. int i, len;
  564. char *p;
  565. char buf[SUBLEN + 1];
  566. LDAPDebug( LDAP_DEBUG_TRACE, "=> substring_comp_keys (%s) %d\n",
  567. str, prepost, 0 );
  568. len = strlen( str );
  569. /* prepend ^ for initial substring */
  570. if ( prepost == '^' )
  571. {
  572. buf[0] = '^';
  573. for ( i = 0; i < SUBLEN - 1; i++ )
  574. {
  575. buf[i + 1] = str[i];
  576. }
  577. buf[SUBLEN] = '\0';
  578. (*ivals)[*nsubs] = slapi_value_new_string(buf);
  579. (*nsubs)++;
  580. }
  581. for ( p = str; p < (str + len - SUBLEN + 1); p++ )
  582. {
  583. for ( i = 0; i < SUBLEN; i++ )
  584. {
  585. buf[i] = p[i];
  586. }
  587. buf[SUBLEN] = '\0';
  588. (*ivals)[*nsubs] = slapi_value_new_string(buf);
  589. (*nsubs)++;
  590. }
  591. if ( prepost == '$' )
  592. {
  593. p = str + len - SUBLEN + 1;
  594. for ( i = 0; i < SUBLEN - 1; i++ )
  595. {
  596. buf[i] = p[i];
  597. }
  598. buf[SUBLEN - 1] = '$';
  599. buf[SUBLEN] = '\0';
  600. (*ivals)[*nsubs] = slapi_value_new_string(buf);
  601. (*nsubs)++;
  602. }
  603. LDAPDebug( LDAP_DEBUG_TRACE, "<= substring_comp_keys\n", 0, 0, 0 );
  604. }