string.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  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. #define MAX_VAL(x,y) ((x)>(y)?(x):(y))
  50. static int string_filter_approx( struct berval *bvfilter,
  51. Slapi_Value **bvals, Slapi_Value **retVal );
  52. static void substring_comp_keys( Slapi_Value ***ivals, int *nsubs, char *str,
  53. int lenstr, int prepost, int syntax, char *comp_buf, int *substrlens );
  54. int
  55. string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax,
  56. int ftype, Slapi_Value **retVal )
  57. {
  58. int i, rc;
  59. struct berval bvfilter_norm;
  60. char *alt = NULL;
  61. if(retVal) {
  62. *retVal = NULL;
  63. }
  64. if ( ftype == LDAP_FILTER_APPROX ) {
  65. return( string_filter_approx( bvfilter, bvals, retVal ) );
  66. }
  67. bvfilter_norm.bv_val = slapi_ch_malloc( bvfilter->bv_len + 1 );
  68. SAFEMEMCPY( bvfilter_norm.bv_val, bvfilter->bv_val, bvfilter->bv_len );
  69. bvfilter_norm.bv_val[bvfilter->bv_len] = '\0';
  70. /* 3rd arg: 1 - trim leading blanks */
  71. value_normalize_ext( bvfilter_norm.bv_val, syntax, 1, &alt );
  72. if (alt) {
  73. slapi_ch_free_string(&bvfilter_norm.bv_val);
  74. bvfilter_norm.bv_val = alt;
  75. }
  76. bvfilter_norm.bv_len = strlen(bvfilter_norm.bv_val);
  77. for ( i = 0; (bvals != NULL) && (bvals[i] != NULL); i++ ) {
  78. rc = value_cmp( (struct berval*)slapi_value_get_berval(bvals[i]), &bvfilter_norm, syntax, 1/* Normalise the first value only */ );
  79. switch ( ftype ) {
  80. case LDAP_FILTER_GE:
  81. if ( rc >= 0 ) {
  82. if(retVal) {
  83. *retVal = bvals[i];
  84. }
  85. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  86. return( 0 );
  87. }
  88. break;
  89. case LDAP_FILTER_LE:
  90. if ( rc <= 0 ) {
  91. if(retVal) {
  92. *retVal = bvals[i];
  93. }
  94. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  95. return( 0 );
  96. }
  97. break;
  98. case LDAP_FILTER_EQUALITY:
  99. if ( rc == 0 ) {
  100. if(retVal) {
  101. *retVal = bvals[i];
  102. }
  103. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  104. return( 0 );
  105. }
  106. break;
  107. }
  108. }
  109. slapi_ch_free ((void**)&bvfilter_norm.bv_val);
  110. return( -1 );
  111. }
  112. /*
  113. * return value: 0 -- approximately matched
  114. * -1 -- did not match
  115. */
  116. static int
  117. string_filter_approx( struct berval *bvfilter, Slapi_Value **bvals,
  118. Slapi_Value **retVal)
  119. {
  120. int i, rc;
  121. int ava_wordcount;
  122. char *w1, *w2, *c1, *c2;
  123. /*
  124. * try to match words in each filter value in order
  125. * in the attribute value.
  126. * XXX should do this once for the filter and save it XXX
  127. */
  128. rc = -1;
  129. if(retVal) {
  130. *retVal = NULL;
  131. }
  132. for ( i = 0; (bvals != NULL) && (bvals[i] != NULL); i++ ) {
  133. w2 = (char*)slapi_value_get_string(bvals[i]); /* JCM cast */
  134. ava_wordcount = 0;
  135. /* for each word in the filter value */
  136. for ( w1 = first_word( bvfilter->bv_val ); w1 != NULL;
  137. w1 = next_word( w1 ) ) {
  138. ++ava_wordcount;
  139. if ( (c1 = phonetic( w1 )) == NULL ) {
  140. break;
  141. }
  142. /*
  143. * for each word in the attribute value from
  144. * where we left off...
  145. */
  146. for ( w2 = first_word( w2 ); w2 != NULL;
  147. w2 = next_word( w2 ) ) {
  148. c2 = phonetic( w2 );
  149. rc = strcmp( c1, c2 );
  150. slapi_ch_free((void**)&c2 );
  151. if ( rc == 0 ) {
  152. if(retVal) {
  153. *retVal = bvals[i];
  154. }
  155. break;
  156. }
  157. }
  158. slapi_ch_free((void**)&c1 );
  159. /*
  160. * if we stopped because we ran out of words
  161. * before making a match, go on to the next
  162. * value. otherwise try to keep matching
  163. * words in this value from where we left off.
  164. */
  165. if ( w2 == NULL ) {
  166. break;
  167. } else {
  168. w2 = next_word( w2 );
  169. }
  170. }
  171. /*
  172. * if we stopped because we ran out of words and
  173. * we found at leasy one word, we have a match.
  174. */
  175. if ( w1 == NULL && ava_wordcount > 0 ) {
  176. rc = 0;
  177. break;
  178. }
  179. }
  180. if (0 != rc) {
  181. rc = -1;
  182. }
  183. LDAPDebug( LDAP_DEBUG_TRACE, "<= string_filter_approx %d\n",
  184. rc, 0, 0 );
  185. return( rc );
  186. }
  187. int
  188. string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
  189. Slapi_Value **bvals, int syntax )
  190. {
  191. int i, j, rc, size=0;
  192. char *p, *end, *realval, *tmpbuf, *bigpat = NULL;
  193. size_t tmpbufsize;
  194. char pat[BUFSIZ];
  195. char buf[BUFSIZ];
  196. char ebuf[BUFSIZ];
  197. time_t curtime = 0;
  198. time_t time_up = 0;
  199. time_t optime = 0; /* time op was initiated */
  200. int timelimit = 0; /* search timelimit */
  201. Operation *op = NULL;
  202. Slapi_Regex *re = NULL;
  203. const char *re_result = NULL;
  204. char *alt = NULL;
  205. LDAPDebug( LDAP_DEBUG_FILTER, "=> string_filter_sub\n",
  206. 0, 0, 0 );
  207. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  208. if (NULL != op) {
  209. slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
  210. slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
  211. } else {
  212. /* timelimit is not passed via pblock */
  213. timelimit = -1;
  214. }
  215. /*
  216. * (timelimit==-1) means no time limit
  217. */
  218. time_up = ( timelimit==-1 ? -1 : optime + timelimit);
  219. /*
  220. * construct a regular expression corresponding to the
  221. * filter and let regex do the work for each value
  222. * XXX should do this once and save it somewhere XXX
  223. */
  224. pat[0] = '\0';
  225. p = pat;
  226. end = pat + sizeof(pat) - 2; /* leave room for null */
  227. if ( initial != NULL ) {
  228. size = strlen( initial ) + 1; /* add 1 for "^" */
  229. }
  230. if ( any != NULL ) {
  231. i = 0;
  232. while ( any[i] ) {
  233. size += strlen(any[i++]) + 2; /* add 2 for ".*" */
  234. }
  235. }
  236. if ( final != NULL ) {
  237. size += strlen( final ) + 3; /* add 3 for ".*" and "$" */
  238. }
  239. size *= 2; /* doubled in case all filter chars need escaping */
  240. size++; /* add 1 for null */
  241. if ( p + size > end ) {
  242. bigpat = slapi_ch_malloc( size );
  243. p = bigpat;
  244. }
  245. if ( initial != NULL ) {
  246. /* 3rd arg: 1 - trim leading blanks */
  247. value_normalize_ext( initial, syntax, 1, &alt );
  248. *p++ = '^';
  249. if (alt) {
  250. filter_strcpy_special_ext( p, alt, FILTER_STRCPY_ESCAPE_RECHARS );
  251. slapi_ch_free_string(&alt);
  252. } else {
  253. filter_strcpy_special_ext( p, initial, FILTER_STRCPY_ESCAPE_RECHARS );
  254. }
  255. p = strchr( p, '\0' );
  256. }
  257. if ( any != NULL ) {
  258. for ( i = 0; any[i] != NULL; i++ ) {
  259. /* 3rd arg: 0 - DO NOT trim leading blanks */
  260. value_normalize_ext( any[i], syntax, 0, &alt );
  261. /* ".*" + value */
  262. *p++ = '.';
  263. *p++ = '*';
  264. if (alt) {
  265. filter_strcpy_special_ext( p, alt, FILTER_STRCPY_ESCAPE_RECHARS );
  266. slapi_ch_free_string(&alt);
  267. } else {
  268. filter_strcpy_special_ext( p, any[i], FILTER_STRCPY_ESCAPE_RECHARS );
  269. }
  270. p = strchr( p, '\0' );
  271. }
  272. }
  273. if ( final != NULL ) {
  274. /* 3rd arg: 0 - DO NOT trim leading blanks */
  275. value_normalize_ext( final, syntax, 0, &alt );
  276. /* ".*" + value */
  277. *p++ = '.';
  278. *p++ = '*';
  279. if (alt) {
  280. filter_strcpy_special_ext( p, alt, FILTER_STRCPY_ESCAPE_RECHARS );
  281. slapi_ch_free_string(&alt);
  282. } else {
  283. filter_strcpy_special_ext( p, final, FILTER_STRCPY_ESCAPE_RECHARS );
  284. }
  285. strcat( p, "$" );
  286. }
  287. /* compile the regex */
  288. p = (bigpat) ? bigpat : pat;
  289. tmpbuf = NULL;
  290. re = slapi_re_comp( p, &re_result );
  291. if (NULL == re) {
  292. LDAPDebug( LDAP_DEBUG_ANY, "re_comp (%s) failed (%s): %s\n",
  293. pat, p, re_result?re_result:"unknown" );
  294. rc = LDAP_OPERATIONS_ERROR;
  295. goto bailout;
  296. } else {
  297. LDAPDebug( LDAP_DEBUG_TRACE, "re_comp (%s)\n",
  298. escape_string( p, ebuf ), 0, 0 );
  299. }
  300. curtime = current_time();
  301. if ( time_up != -1 && curtime > time_up ) {
  302. rc = LDAP_TIMELIMIT_EXCEEDED;
  303. goto bailout;
  304. }
  305. /*
  306. * test the regex against each value
  307. */
  308. rc = -1;
  309. tmpbuf = NULL;
  310. tmpbufsize = 0;
  311. for ( j = 0; (bvals != NULL) && (bvals[j] != NULL); j++ ) {
  312. int tmprc;
  313. size_t len;
  314. const struct berval *bvp = slapi_value_get_berval(bvals[j]);
  315. len = bvp->bv_len;
  316. if ( len < sizeof(buf) ) {
  317. strcpy( buf, bvp->bv_val );
  318. realval = buf;
  319. } else if ( len < tmpbufsize ) {
  320. strcpy( buf, bvp->bv_val );
  321. realval = tmpbuf;
  322. } else {
  323. tmpbuf = (char *) slapi_ch_realloc( tmpbuf, len + 1 );
  324. strcpy( tmpbuf, bvp->bv_val );
  325. realval = tmpbuf;
  326. }
  327. /* 3rd arg: 1 - trim leading blanks */
  328. value_normalize_ext( realval, syntax, 1, &alt );
  329. if (alt) {
  330. tmprc = slapi_re_exec( re, alt, time_up );
  331. slapi_ch_free_string(&alt);
  332. } else {
  333. tmprc = slapi_re_exec( re, realval, time_up );
  334. }
  335. LDAPDebug( LDAP_DEBUG_TRACE, "re_exec (%s) %i\n",
  336. escape_string( realval, ebuf ), tmprc, 0 );
  337. if ( tmprc == 1 ) {
  338. rc = 0;
  339. break;
  340. } else if ( tmprc != 0 ) {
  341. rc = tmprc;
  342. break;
  343. }
  344. }
  345. bailout:
  346. slapi_re_free(re);
  347. slapi_ch_free((void**)&tmpbuf ); /* NULL is fine */
  348. slapi_ch_free((void**)&bigpat ); /* NULL is fine */
  349. LDAPDebug( LDAP_DEBUG_FILTER, "<= string_filter_sub %d\n",
  350. rc, 0, 0 );
  351. return( rc );
  352. }
  353. int
  354. string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,
  355. Slapi_Value ***ivals, int syntax, int ftype )
  356. {
  357. int nsubs, numbvals = 0, n;
  358. Slapi_Value **nbvals, **nbvlp;
  359. Slapi_Value **bvlp;
  360. char *w, *c, *p;
  361. char *alt = NULL;
  362. if (NULL == ivals) {
  363. return 1;
  364. }
  365. *ivals = NULL;
  366. if (NULL == bvals) {
  367. return 1;
  368. }
  369. switch ( ftype ) {
  370. case LDAP_FILTER_EQUALITY:
  371. /* allocate a new array for the normalized values */
  372. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  373. numbvals++;
  374. }
  375. nbvals = (Slapi_Value **) slapi_ch_calloc( (numbvals + 1), sizeof(Slapi_Value *));
  376. for ( bvlp = bvals, nbvlp = nbvals; bvlp && *bvlp; bvlp++, nbvlp++ )
  377. {
  378. c = slapi_ch_strdup(slapi_value_get_string(*bvlp));
  379. /* if the NORMALIZED flag is set, skip normalizing */
  380. if (!(slapi_value_get_flags(*bvlp) & SLAPI_ATTR_FLAG_NORMALIZED)) {
  381. /* 3rd arg: 1 - trim leading blanks */
  382. value_normalize_ext( c, syntax, 1, &alt );
  383. }
  384. if (alt) {
  385. slapi_ch_free_string(&c);
  386. *nbvlp = slapi_value_new_string_passin(alt);
  387. } else {
  388. *nbvlp = slapi_value_new_string_passin(c);
  389. }
  390. }
  391. *ivals = nbvals;
  392. break;
  393. case LDAP_FILTER_APPROX:
  394. /* XXX should not do this twice! XXX */
  395. /* get an upper bound on the number of ivals */
  396. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  397. for ( w = first_word( (char*)slapi_value_get_string(*bvlp) );
  398. w != NULL; w = next_word( w ) ) {
  399. numbvals++;
  400. }
  401. }
  402. nbvals = (Slapi_Value **) slapi_ch_calloc( (numbvals + 1), sizeof(Slapi_Value *) );
  403. n = 0;
  404. nbvlp = nbvals;
  405. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  406. for ( w = first_word( (char*)slapi_value_get_string(*bvlp) );
  407. w != NULL; w = next_word( w ) ) {
  408. if ( (c = phonetic( w )) != NULL ) {
  409. *nbvlp = slapi_value_new_string_passin(c);
  410. nbvlp++;
  411. }
  412. }
  413. }
  414. /* even if (n == 0), we should return the array nbvals w/ NULL items */
  415. *ivals = nbvals;
  416. break;
  417. case LDAP_FILTER_SUBSTRINGS:
  418. {
  419. /* XXX should remove duplicates! XXX */
  420. Slapi_Value *bvdup;
  421. const struct berval *bvp;
  422. char *buf;
  423. int i;
  424. int *substrlens = NULL;
  425. int localsublens[3] = {SUBBEGIN, SUBMIDDLE, SUBEND};/* default values */
  426. int maxsublen;
  427. /*
  428. * Substring key has 3 types:
  429. * begin (e.g., *^a)
  430. * middle (e.g., *abc)
  431. * end (e.g., *xy$)
  432. *
  433. * the each has its own key length, which can be configured as follows:
  434. * Usage: turn an index object to extensibleobject and
  435. * set an integer value for each.
  436. * dn: cn=sn, cn=index, cn=userRoot, cn=ldbm database, cn=plugins,
  437. * cn=config
  438. * objectClass: extensibleObject
  439. * nsSubStrBegin: 2
  440. * nsSubStrMiddle: 3
  441. * nsSubStrEnd: 2
  442. * [...]
  443. *
  444. * By default, begin == 3, middle == 3, end == 3 (defined in syntax.h)
  445. */
  446. /* If nsSubStrLen is specified in each index entry,
  447. respect the length for the substring index key length.
  448. Otherwise, the deafult value SUBLEN is used */
  449. slapi_pblock_get(pb, SLAPI_SYNTAX_SUBSTRLENS, &substrlens);
  450. if (NULL == substrlens) {
  451. substrlens = localsublens;
  452. }
  453. if (0 == substrlens[INDEX_SUBSTRBEGIN]) {
  454. substrlens[INDEX_SUBSTRBEGIN] = SUBBEGIN;
  455. }
  456. if (0 == substrlens[INDEX_SUBSTRMIDDLE]) {
  457. substrlens[INDEX_SUBSTRMIDDLE] = SUBMIDDLE;
  458. }
  459. if (0 == substrlens[INDEX_SUBSTREND]) {
  460. substrlens[INDEX_SUBSTREND] = SUBEND;
  461. }
  462. maxsublen = MAX_VAL(substrlens[INDEX_SUBSTRBEGIN], substrlens[INDEX_SUBSTRMIDDLE]);
  463. maxsublen = MAX_VAL(maxsublen, substrlens[INDEX_SUBSTREND]);
  464. buf = (char *)slapi_ch_calloc(1, maxsublen + 1);
  465. nsubs = 0;
  466. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  467. /*
  468. * Note: this calculation may err on the high side,
  469. * because value_normalize_ext(), which is called below
  470. * before we actually create the substring keys, may
  471. * reduce the length of the value in some cases or
  472. * increase the length in other cases. For example,
  473. * spaces are removed when space insensitive strings
  474. * are normalized. Or if the value includes '\"' (2 bytes),
  475. * it's normalized to '\22' (3 bytes). But it's okay
  476. * for nsubs to be too big. Since the ivals array is
  477. * NULL terminated, the only downside is that we
  478. * allocate more space than we really need.
  479. */
  480. nsubs += slapi_value_get_length(*bvlp) - substrlens[INDEX_SUBSTRMIDDLE] + 3;
  481. }
  482. nsubs += substrlens[INDEX_SUBSTRMIDDLE] * 2 - substrlens[INDEX_SUBSTRBEGIN] - substrlens[INDEX_SUBSTREND];
  483. *ivals = (Slapi_Value **) slapi_ch_calloc( (nsubs + 1), sizeof(Slapi_Value *) );
  484. n = 0;
  485. bvdup= slapi_value_new();
  486. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  487. c = slapi_ch_strdup(slapi_value_get_string(*bvlp));
  488. /* 3rd arg: 1 - trim leading blanks */
  489. value_normalize_ext( c, syntax, 1, &alt );
  490. if (alt) {
  491. slapi_ch_free_string(&c);
  492. slapi_value_set_string_passin(bvdup, alt);
  493. } else {
  494. slapi_value_set_string_passin(bvdup, c);
  495. }
  496. bvp = slapi_value_get_berval(bvdup);
  497. /* leading */
  498. if ( bvp->bv_len > substrlens[INDEX_SUBSTRBEGIN] - 2 ) {
  499. buf[0] = '^';
  500. for ( i = 0; i < substrlens[INDEX_SUBSTRBEGIN] - 1; i++ ) {
  501. buf[i + 1] = bvp->bv_val[i];
  502. }
  503. buf[substrlens[INDEX_SUBSTRBEGIN]] = '\0';
  504. (*ivals)[n] = slapi_value_new_string(buf);
  505. n++;
  506. }
  507. /* any */
  508. for ( p = bvp->bv_val;
  509. p < (bvp->bv_val + bvp->bv_len - substrlens[INDEX_SUBSTRMIDDLE] + 1);
  510. p++ ) {
  511. for ( i = 0; i < substrlens[INDEX_SUBSTRMIDDLE]; i++ ) {
  512. buf[i] = p[i];
  513. }
  514. buf[substrlens[INDEX_SUBSTRMIDDLE]] = '\0';
  515. (*ivals)[n] = slapi_value_new_string(buf);
  516. n++;
  517. }
  518. /* trailing */
  519. if ( bvp->bv_len > substrlens[INDEX_SUBSTREND] - 2 ) {
  520. p = bvp->bv_val + bvp->bv_len - substrlens[INDEX_SUBSTREND] + 1;
  521. for ( i = 0; i < substrlens[INDEX_SUBSTREND] - 1; i++ ) {
  522. buf[i] = p[i];
  523. }
  524. buf[substrlens[INDEX_SUBSTREND] - 1] = '$';
  525. buf[substrlens[INDEX_SUBSTREND]] = '\0';
  526. (*ivals)[n] = slapi_value_new_string(buf);
  527. n++;
  528. }
  529. }
  530. slapi_value_free(&bvdup);
  531. slapi_ch_free_string(&buf);
  532. }
  533. break;
  534. }
  535. return( 0 );
  536. }
  537. /* we've added code to make our equality filter processing faster */
  538. int
  539. string_assertion2keys_ava(
  540. Slapi_PBlock *pb,
  541. Slapi_Value *val,
  542. Slapi_Value ***ivals,
  543. int syntax,
  544. int ftype
  545. )
  546. {
  547. int i, numbvals;
  548. size_t len;
  549. char *w, *c;
  550. Slapi_Value *tmpval=NULL;
  551. char *alt = NULL;
  552. switch ( ftype ) {
  553. case LDAP_FILTER_EQUALITY_FAST:
  554. /* this code is trying to avoid multiple malloc/frees */
  555. len=slapi_value_get_length(val);
  556. tmpval=(*ivals)[0];
  557. if (len >= tmpval->bv.bv_len) {
  558. tmpval->bv.bv_val=(char *)slapi_ch_malloc(len+1);
  559. }
  560. memcpy(tmpval->bv.bv_val,slapi_value_get_string(val),len);
  561. tmpval->bv.bv_val[len]='\0';
  562. /* 3rd arg: 1 - trim leading blanks */
  563. value_normalize_ext(tmpval->bv.bv_val, syntax, 1, &alt );
  564. if (alt) {
  565. if (len >= tmpval->bv.bv_len) {
  566. slapi_ch_free_string(&tmpval->bv.bv_val);
  567. }
  568. tmpval->bv.bv_val = alt;
  569. }
  570. tmpval->bv.bv_len=strlen(tmpval->bv.bv_val);
  571. break;
  572. case LDAP_FILTER_EQUALITY:
  573. (*ivals) = (Slapi_Value **) slapi_ch_malloc( 2 * sizeof(Slapi_Value *) );
  574. (*ivals)[0] = slapi_value_dup( val );
  575. /* 3rd arg: 1 - trim leading blanks */
  576. value_normalize_ext( (*ivals)[0]->bv.bv_val, syntax, 1, &alt );
  577. if (alt) {
  578. slapi_ch_free_string(&(*ivals)[0]->bv.bv_val);
  579. (*ivals)[0]->bv.bv_val = alt;
  580. }
  581. (*ivals)[0]->bv.bv_len = strlen( (*ivals)[0]->bv.bv_val );
  582. (*ivals)[1] = NULL;
  583. break;
  584. case LDAP_FILTER_APPROX:
  585. /* XXX should not do this twice! XXX */
  586. /* get an upper bound on the number of ivals */
  587. numbvals = 0;
  588. for ( w = first_word( (char*)slapi_value_get_string(val) ); w != NULL;
  589. w = next_word( w ) ) {
  590. numbvals++;
  591. }
  592. (*ivals) = (Slapi_Value **) slapi_ch_malloc( (numbvals + 1) *
  593. sizeof(Slapi_Value *) );
  594. i = 0;
  595. for ( w = first_word( (char*)slapi_value_get_string(val) ); w != NULL;
  596. w = next_word( w ) ) {
  597. if ( (c = phonetic( w )) != NULL ) {
  598. (*ivals)[i] = slapi_value_new_string_passin(c);
  599. i++;
  600. }
  601. }
  602. (*ivals)[i] = NULL;
  603. if ( i == 0 ) {
  604. slapi_ch_free((void**)ivals );
  605. return( 0 );
  606. }
  607. break;
  608. default:
  609. LDAPDebug( LDAP_DEBUG_ANY,
  610. "string_assertion2keys_ava: unknown ftype 0x%x\n",
  611. ftype, 0, 0 );
  612. break;
  613. }
  614. return( 0 );
  615. }
  616. int
  617. string_assertion2keys_sub(
  618. Slapi_PBlock *pb,
  619. char *initial,
  620. char **any,
  621. char *final,
  622. Slapi_Value ***ivals,
  623. int syntax
  624. )
  625. {
  626. int nsubs, i, len;
  627. int initiallen = 0, finallen = 0;
  628. int *substrlens = NULL;
  629. int localsublens[3] = {SUBBEGIN, SUBMIDDLE, SUBEND};/* default values */
  630. int maxsublen;
  631. char *comp_buf = NULL;
  632. char *altinit = NULL;
  633. char *oaltinit = NULL;
  634. char **altany = NULL;
  635. char **oaltany = NULL;
  636. char *altfinal = NULL;
  637. char *oaltfinal = NULL;
  638. int anysize = 0;
  639. slapi_pblock_get(pb, SLAPI_SYNTAX_SUBSTRLENS, &substrlens);
  640. if (NULL == substrlens) {
  641. substrlens = localsublens;
  642. }
  643. if (0 == substrlens[INDEX_SUBSTRBEGIN]) {
  644. substrlens[INDEX_SUBSTRBEGIN] = SUBBEGIN;
  645. }
  646. if (0 == substrlens[INDEX_SUBSTRMIDDLE]) {
  647. substrlens[INDEX_SUBSTRMIDDLE] = SUBMIDDLE;
  648. }
  649. if (0 == substrlens[INDEX_SUBSTREND]) {
  650. substrlens[INDEX_SUBSTREND] = SUBEND;
  651. }
  652. *ivals = NULL;
  653. /*
  654. * First figure out how many keys we will return. The answer is based
  655. * on the length of each assertion value. Since normalization may
  656. * reduce the length (such as when spaces are removed from space
  657. * insensitive strings), we call value_normalize_ext() before checking
  658. * the length.
  659. */
  660. nsubs = 0;
  661. if ( initial != NULL ) {
  662. /* 3rd arg: 0 - DO NOT trim leading blanks */
  663. value_normalize_ext( initial, syntax, 0, &altinit );
  664. oaltinit = altinit;
  665. if (NULL == altinit) {
  666. altinit = initial;
  667. }
  668. initiallen = strlen( altinit );
  669. if ( initiallen > substrlens[INDEX_SUBSTRBEGIN] - 2 ) {
  670. nsubs += 1; /* for the initial begin string key */
  671. /* the rest of the sub keys are "any" keys for this case */
  672. if ( initiallen >= substrlens[INDEX_SUBSTRMIDDLE] ) {
  673. nsubs += initiallen - substrlens[INDEX_SUBSTRMIDDLE] + 1;
  674. }
  675. } else {
  676. altinit = NULL; /* save some work later */
  677. }
  678. }
  679. for ( i = 0; any != NULL && any[i] != NULL; i++ ) {
  680. anysize++;
  681. }
  682. altany = (char **)slapi_ch_calloc(anysize + 1, sizeof(char *));
  683. oaltany = (char **)slapi_ch_calloc(anysize + 1, sizeof(char *));
  684. for ( i = 0; any != NULL && any[i] != NULL; i++ ) {
  685. /* 3rd arg: 0 - DO NOT trim leading blanks */
  686. value_normalize_ext( any[i], syntax, 0, &altany[i] );
  687. if (NULL == altany[i]) {
  688. altany[i] = any[i];
  689. } else {
  690. oaltany[i] = altany[i];
  691. }
  692. len = strlen( altany[i] );
  693. if ( len >= substrlens[INDEX_SUBSTRMIDDLE] ) {
  694. nsubs += len - substrlens[INDEX_SUBSTRMIDDLE] + 1;
  695. }
  696. }
  697. if ( final != NULL ) {
  698. /* 3rd arg: 0 - DO NOT trim leading blanks */
  699. value_normalize_ext( final, syntax, 0, &altfinal );
  700. oaltfinal = altfinal;
  701. if (NULL == altfinal) {
  702. altfinal = final;
  703. }
  704. finallen = strlen( altfinal );
  705. if ( finallen > substrlens[INDEX_SUBSTREND] - 2 ) {
  706. nsubs += 1; /* for the final end string key */
  707. /* the rest of the sub keys are "any" keys for this case */
  708. if ( finallen >= substrlens[INDEX_SUBSTRMIDDLE] ) {
  709. nsubs += finallen - substrlens[INDEX_SUBSTRMIDDLE] + 1;
  710. }
  711. } else {
  712. altfinal = NULL; /* save some work later */
  713. }
  714. }
  715. if ( nsubs == 0 ) { /* no keys to return */
  716. return( 0 );
  717. }
  718. /*
  719. * Next, allocated the ivals array and fill it in with the actual
  720. * keys. *ivals is a NULL terminated array of Slapi_Value pointers.
  721. */
  722. *ivals = (Slapi_Value **) slapi_ch_malloc( (nsubs + 1) * sizeof(Slapi_Value *) );
  723. maxsublen = MAX_VAL(substrlens[INDEX_SUBSTRBEGIN], substrlens[INDEX_SUBSTRMIDDLE]);
  724. maxsublen = MAX_VAL(maxsublen, substrlens[INDEX_SUBSTREND]);
  725. nsubs = 0;
  726. comp_buf = (char *)slapi_ch_malloc(maxsublen + 1);
  727. if ( altinit != NULL ) {
  728. substring_comp_keys( ivals, &nsubs, altinit, initiallen, '^', syntax,
  729. comp_buf, substrlens );
  730. }
  731. slapi_ch_free_string(&oaltinit);
  732. for ( i = 0; altany != NULL && altany[i] != NULL; i++ ) {
  733. len = strlen( altany[i] );
  734. if ( len < substrlens[INDEX_SUBSTRMIDDLE] ) {
  735. continue;
  736. }
  737. substring_comp_keys( ivals, &nsubs, altany[i], len, 0, syntax,
  738. comp_buf, substrlens );
  739. slapi_ch_free_string(&oaltany[i]);
  740. }
  741. slapi_ch_free((void **)&oaltany);
  742. slapi_ch_free((void **)&altany);
  743. if ( altfinal != NULL ) {
  744. substring_comp_keys( ivals, &nsubs, altfinal, finallen, '$', syntax,
  745. comp_buf, substrlens );
  746. }
  747. slapi_ch_free_string(&oaltfinal);
  748. (*ivals)[nsubs] = NULL;
  749. slapi_ch_free_string(&comp_buf);
  750. return( 0 );
  751. }
  752. static void
  753. substring_comp_keys(
  754. Slapi_Value ***ivals,
  755. int *nsubs,
  756. char *str,
  757. int lenstr,
  758. int prepost,
  759. int syntax,
  760. char *comp_buf,
  761. int *substrlens
  762. )
  763. {
  764. int i, substrlen;
  765. char *p;
  766. PR_ASSERT(NULL != comp_buf);
  767. PR_ASSERT(NULL != substrlens);
  768. LDAPDebug( LDAP_DEBUG_TRACE, "=> substring_comp_keys (%s) %d\n",
  769. str, prepost, 0 );
  770. /* prepend ^ for initial substring */
  771. if ( prepost == '^' )
  772. {
  773. substrlen = substrlens[INDEX_SUBSTRBEGIN];
  774. comp_buf[0] = '^';
  775. for ( i = 0; i < substrlen - 1; i++ )
  776. {
  777. comp_buf[i + 1] = str[i];
  778. }
  779. comp_buf[substrlen] = '\0';
  780. (*ivals)[*nsubs] = slapi_value_new_string(comp_buf);
  781. (*nsubs)++;
  782. }
  783. substrlen = substrlens[INDEX_SUBSTRMIDDLE];
  784. for ( p = str; p < (str + lenstr - substrlen + 1); p++ )
  785. {
  786. for ( i = 0; i < substrlen; i++ )
  787. {
  788. comp_buf[i] = p[i];
  789. }
  790. comp_buf[substrlen] = '\0';
  791. (*ivals)[*nsubs] = slapi_value_new_string(comp_buf);
  792. (*nsubs)++;
  793. }
  794. if ( prepost == '$' )
  795. {
  796. substrlen = substrlens[INDEX_SUBSTREND];
  797. p = str + lenstr - substrlen + 1;
  798. for ( i = 0; i < substrlen - 1; i++ )
  799. {
  800. comp_buf[i] = p[i];
  801. }
  802. comp_buf[substrlen - 1] = '$';
  803. comp_buf[substrlen] = '\0';
  804. (*ivals)[*nsubs] = slapi_value_new_string(comp_buf);
  805. (*nsubs)++;
  806. }
  807. LDAPDebug( LDAP_DEBUG_TRACE, "<= substring_comp_keys\n", 0, 0, 0 );
  808. }