2 * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5 * schema.c: parsing routines used by servers and clients to process
15 #include <ac/string.h>
20 #include <ldap_schema.h>
23 * When pretty printing the entities we will be appending to a buffer.
24 * Since checking for overflow, realloc'ing and checking if no error
25 * is extremely boring, we will use a protection layer that will let
26 * us blissfully ignore the error until the end. This layer is
27 * implemented with the help of the next type.
30 typedef struct safe_string {
38 new_safe_string(int size)
42 ss = LDAP_MALLOC(sizeof(safe_string));
47 ss->val = LDAP_MALLOC(size);
57 safe_string_free(safe_string * ss)
61 ldap_memfree(ss->val);
66 safe_string_val(safe_string * ss)
68 ss->val[ss->pos] = '\0';
73 append_to_safe_string(safe_string * ss, char * s)
79 * Some runaway process is trying to append to a string that
80 * overflowed and we could not extend.
85 /* We always make sure there is at least one position available */
86 if ( ss->pos + l >= ss->size-1 ) {
88 temp = LDAP_REALLOC(ss->val, ss->size);
90 /* Trouble, out of memory */
96 strncpy(&ss->val[ss->pos], s, l);
98 if ( ss->pos > 0 && ss->val[ss->pos-1] == ' ' )
107 print_literal(safe_string *ss, char *s)
109 return(append_to_safe_string(ss,s));
113 print_whsp(safe_string *ss)
116 return(append_to_safe_string(ss,""));
118 return(append_to_safe_string(ss," "));
122 print_numericoid(safe_string *ss, char *s)
125 return(append_to_safe_string(ss,s));
128 /* This one is identical to print_qdescr */
130 print_qdstring(safe_string *ss, char *s)
133 print_literal(ss,"'");
134 append_to_safe_string(ss,s);
135 print_literal(ss,"'");
136 return(print_whsp(ss));
140 print_qdescr(safe_string *ss, char *s)
143 print_literal(ss,"'");
144 append_to_safe_string(ss,s);
145 print_literal(ss,"'");
146 return(print_whsp(ss));
150 print_qdescrlist(safe_string *ss, char **sa)
155 for (sp=sa; *sp; sp++) {
156 ret = print_qdescr(ss,*sp);
158 /* If the list was empty, we return zero that is potentially
159 * incorrect, but since we will be still appending things, the
160 * overflow will be detected later. Maybe FIX.
166 print_qdescrs(safe_string *ss, char **sa)
168 /* The only way to represent an empty list is as a qdescrlist
169 * so, if the list is empty we treat it as a long list.
170 * Really, this is what the syntax mandates. We should not
171 * be here if the list was empty, but if it happens, a label
172 * has already been output and we cannot undo it.
174 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
176 print_literal(ss,"(");
177 print_qdescrlist(ss,sa);
178 print_literal(ss,")");
179 return(print_whsp(ss));
181 return(print_qdescr(ss,*sa));
186 print_woid(safe_string *ss, char *s)
189 append_to_safe_string(ss,s);
190 return print_whsp(ss);
194 print_oidlist(safe_string *ss, char **sa)
198 for (sp=sa; *(sp+1); sp++) {
200 print_literal(ss,"$");
202 return(print_woid(ss,*sp));
206 print_oids(safe_string *ss, char **sa)
208 if ( sa[0] && sa[1] ) {
209 print_literal(ss,"(");
210 print_oidlist(ss,sa);
212 return(print_literal(ss,")"));
214 return(print_woid(ss,*sa));
219 print_noidlen(safe_string *ss, char *s, int l)
224 ret = print_numericoid(ss,s);
226 sprintf(buf,"{%d}",l);
227 ret = print_literal(ss,buf);
233 ldap_syntax2str( LDAP_SYNTAX * syn )
238 ss = new_safe_string(256);
242 print_literal(ss,"(");
245 print_numericoid(ss, syn->syn_oid);
248 if ( syn->syn_desc ) {
249 print_literal(ss,"DESC");
250 print_qdstring(ss,syn->syn_desc);
254 print_literal(ss,")");
256 retstring = strdup(safe_string_val(ss));
257 safe_string_free(ss);
262 ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
267 ss = new_safe_string(256);
271 print_literal(ss,"(");
274 print_numericoid(ss, oc->oc_oid);
277 if ( oc->oc_names ) {
278 print_literal(ss,"NAME");
279 print_qdescrs(ss,oc->oc_names);
283 print_literal(ss,"DESC");
284 print_qdstring(ss,oc->oc_desc);
287 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
288 print_literal(ss, "OBSOLETE");
292 if ( oc->oc_sup_oids ) {
293 print_literal(ss,"SUP");
294 print_oids(ss,oc->oc_sup_oids);
297 switch (oc->oc_kind) {
298 case LDAP_SCHEMA_ABSTRACT:
299 print_literal(ss,"ABSTRACT");
301 case LDAP_SCHEMA_STRUCTURAL:
302 print_literal(ss,"STRUCTURAL");
304 case LDAP_SCHEMA_AUXILIARY:
305 print_literal(ss,"AUXILIARY");
308 print_literal(ss,"KIND-UNKNOWN");
313 if ( oc->oc_at_oids_must ) {
314 print_literal(ss,"MUST");
316 print_oids(ss,oc->oc_at_oids_must);
320 if ( oc->oc_at_oids_may ) {
321 print_literal(ss,"MAY");
323 print_oids(ss,oc->oc_at_oids_may);
328 print_literal(ss,")");
330 retstring = strdup(safe_string_val(ss));
331 safe_string_free(ss);
336 ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
341 ss = new_safe_string(256);
345 print_literal(ss,"(");
348 print_numericoid(ss, at->at_oid);
351 if ( at->at_names ) {
352 print_literal(ss,"NAME");
353 print_qdescrs(ss,at->at_names);
357 print_literal(ss,"DESC");
358 print_qdstring(ss,at->at_desc);
361 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
362 print_literal(ss, "OBSOLETE");
366 if ( at->at_sup_oid ) {
367 print_literal(ss,"SUP");
368 print_woid(ss,at->at_sup_oid);
371 if ( at->at_equality_oid ) {
372 print_literal(ss,"EQUALITY");
373 print_woid(ss,at->at_equality_oid);
376 if ( at->at_ordering_oid ) {
377 print_literal(ss,"ORDERING");
378 print_woid(ss,at->at_ordering_oid);
381 if ( at->at_substr_oid ) {
382 print_literal(ss,"SUBSTR");
383 print_woid(ss,at->at_substr_oid);
386 if ( at->at_syntax_oid ) {
387 print_literal(ss,"SYNTAX");
389 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
392 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
393 print_literal(ss,"SINGLE-VALUE");
397 if ( at->at_collective == LDAP_SCHEMA_YES ) {
398 print_literal(ss,"COLLECTIVE");
402 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
403 print_literal(ss,"NO-USER-MODIFICATION");
407 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
408 print_literal(ss,"USAGE");
410 switch (at->at_usage) {
411 case LDAP_SCHEMA_DIRECTORY_OPERATION:
412 print_literal(ss,"directoryOperation");
414 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
415 print_literal(ss,"distributedOperation");
417 case LDAP_SCHEMA_DSA_OPERATION:
418 print_literal(ss,"dSAOperation");
421 print_literal(ss,"UNKNOWN");
427 print_literal(ss,")");
429 retstring = strdup(safe_string_val(ss));
430 safe_string_free(ss);
435 * This is ripped from servers/slapd/charray.c that should be promoted
436 * to -lldap or something so that it is used everywhere.
439 charray_free( char **array )
443 if ( array == NULL ) {
447 for ( a = array; *a != NULL; a++ ) {
452 LDAP_FREE( (char *) array );
456 * Now come the parsers. There is one parser for each entity type:
457 * objectclasses, attributetypes, etc.
459 * Each of them is written as a recursive-descent parser, except that
460 * none of them is really recursive. But the idea is kept: there
461 * is one routine per non-terminal that eithers gobbles lexical tokens
462 * or calls lower-level routines, etc.
464 * The scanner is implemented in the routine get_token. Actually,
465 * get_token is more than a scanner and will return tokens that are
466 * in fact non-terminals in the grammar. So you can see the whole
467 * approach as the combination of a low-level bottom-up recognizer
468 * combined with a scanner and a number of top-down parsers. Or just
469 * consider that the real grammars recognized by the parsers are not
470 * those of the standards. As a matter of fact, our parsers are more
471 * liberal than the spec when there is no ambiguity.
473 * The difference is pretty academic (modulo bugs or incorrect
474 * interpretation of the specs).
477 #define TK_NOENDQUOTE -2
478 #define TK_OUTOFMEM -1
480 #define TK_UNEXPCHAR 1
481 #define TK_BAREWORD 2
482 #define TK_QDSTRING 3
483 #define TK_LEFTPAREN 4
484 #define TK_RIGHTPAREN 5
486 #define TK_QDESCR TK_QDSTRING
494 get_token(char ** sp, char ** token_val)
511 kind = TK_RIGHTPAREN;
522 while ( **sp != '\'' && **sp != '\0' )
524 if ( **sp == '\'' ) {
526 res = LDAP_MALLOC(q-p+1);
536 kind = TK_NOENDQUOTE;
542 while ( !isspace(**sp) && **sp != '\0' )
545 res = LDAP_MALLOC(q-p+1);
554 /* kind = TK_UNEXPCHAR; */
561 /* Gobble optional whitespace */
563 parse_whsp(char **sp)
565 while (isspace(**sp))
570 * General note for all parsers: to guarantee the algorithm halts they
571 * must always advance the pointer even when an error is found. For
572 * this one is not that important since an error here is fatal at the
573 * upper layers, but it is a simple strategy that will not get in
577 /* Parse a sequence of dot-separated decimal strings */
579 parse_numericoid(char **sp, int *code)
585 /* Each iteration of this loops gets one decimal string */
587 if ( !isdigit(**sp) ) {
589 * Initial char is not a digit or char after dot is
592 *code = LDAP_SCHERR_NODIGIT;
596 while ( isdigit(**sp) )
600 /* Otherwise, gobble the dot and loop again */
603 /* Now *sp points at the char past the numericoid. Perfect. */
605 res = LDAP_MALLOC(len+1);
607 *code = LDAP_SCHERR_OUTOFMEM;
610 strncpy(res,start,len);
615 /* Parse a qdescr or a list of them enclosed in () */
617 parse_qdescrs(char **sp, int *code)
627 kind = get_token(sp,&sval);
628 if ( kind == TK_LEFTPAREN ) {
629 /* Let's presume there will be at least 2 entries */
631 res = LDAP_CALLOC(3,sizeof(char *));
633 *code = LDAP_SCHERR_OUTOFMEM;
639 kind = get_token(sp,&sval);
640 if ( kind == TK_RIGHTPAREN )
642 if ( kind == TK_QDESCR ) {
643 if ( pos == size-2 ) {
645 res1 = LDAP_REALLOC(res,size*sizeof(char *));
648 *code = LDAP_SCHERR_OUTOFMEM;
658 *code = LDAP_SCHERR_UNEXPTOKEN;
665 } else if ( kind == TK_QDESCR ) {
666 res = LDAP_CALLOC(2,sizeof(char *));
668 *code = LDAP_SCHERR_OUTOFMEM;
676 *code = LDAP_SCHERR_BADNAME;
683 parse_woid(char **sp, int *code)
689 kind = get_token(sp, &sval);
690 if ( kind != TK_BAREWORD ) {
691 *code = LDAP_SCHERR_UNEXPTOKEN;
698 /* Parse a noidlen */
700 parse_noidlen(char **sp, int *code, int *len)
706 kind = get_token(sp, &sval);
707 if ( kind != TK_BAREWORD ) {
708 *code = LDAP_SCHERR_UNEXPTOKEN;
714 while ( isdigit(**sp) )
718 *code = LDAP_SCHERR_UNEXPTOKEN;
728 * Next routine will accept a qdstring in place of an oid. This is
729 * necessary to interoperate with Netscape Directory server that
730 * will improperly quote each oid (at least those of the descr kind)
734 /* Parse a woid or a $-separated list of them enclosed in () */
736 parse_oids(char **sp, int *code)
746 * Strictly speaking, doing this here accepts whsp before the
747 * ( at the begining of an oidlist, but his is harmless. Also,
748 * we are very liberal in what we accept as an OID. Maybe
752 kind = get_token(sp,&sval);
753 if ( kind == TK_LEFTPAREN ) {
754 /* Let's presume there will be at least 2 entries */
756 res = LDAP_CALLOC(3,sizeof(char *));
758 *code = LDAP_SCHERR_OUTOFMEM;
763 kind = get_token(sp,&sval);
764 if ( kind == TK_BAREWORD || kind == TK_QDSTRING ) {
768 *code = LDAP_SCHERR_UNEXPTOKEN;
774 kind = get_token(sp,&sval);
775 if ( kind == TK_RIGHTPAREN )
777 if ( kind == TK_DOLLAR ) {
779 kind = get_token(sp,&sval);
780 if ( kind == TK_BAREWORD ||
781 kind == TK_QDSTRING ) {
782 if ( pos == size-2 ) {
784 res1 = LDAP_REALLOC(res,size*sizeof(char *));
787 *code = LDAP_SCHERR_OUTOFMEM;
795 *code = LDAP_SCHERR_UNEXPTOKEN;
801 *code = LDAP_SCHERR_UNEXPTOKEN;
809 } else if ( kind == TK_BAREWORD || kind == TK_QDSTRING ) {
810 res = LDAP_CALLOC(2,sizeof(char *));
812 *code = LDAP_SCHERR_OUTOFMEM;
820 *code = LDAP_SCHERR_BADNAME;
826 free_syn(LDAP_SYNTAX * syn)
828 ldap_memfree(syn->syn_oid);
829 ldap_memfree(syn->syn_desc);
834 ldap_str2syntax( char * s, int * code, char ** errp )
844 *code = LDAP_SCHERR_EMPTY;
850 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
853 *code = LDAP_SCHERR_OUTOFMEM;
857 kind = get_token(&ss,&sval);
858 if ( kind != TK_LEFTPAREN ) {
859 *code = LDAP_SCHERR_NOLEFTPAREN;
865 syn->syn_oid = parse_numericoid(&ss,code);
866 if ( !syn->syn_oid ) {
874 * Beyond this point we will be liberal and accept the items
878 kind = get_token(&ss,&sval);
881 *code = LDAP_SCHERR_NORIGHTPAREN;
888 if ( !strcmp(sval,"DESC") ) {
890 *code = LDAP_SCHERR_DUPOPT;
897 kind = get_token(&ss,&sval);
898 if ( kind != TK_QDSTRING ) {
899 *code = LDAP_SCHERR_UNEXPTOKEN;
904 syn->syn_desc = sval;
906 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
907 /* Should be parse_qdstrings */
908 ssdummy = parse_qdescrs(&ss, code);
915 *code = LDAP_SCHERR_UNEXPTOKEN;
922 *code = LDAP_SCHERR_UNEXPTOKEN;
931 free_at(LDAP_ATTRIBUTE_TYPE * at)
933 ldap_memfree(at->at_oid);
934 charray_free(at->at_names);
935 ldap_memfree(at->at_desc);
936 ldap_memfree(at->at_sup_oid);
937 ldap_memfree(at->at_equality_oid);
938 ldap_memfree(at->at_ordering_oid);
939 ldap_memfree(at->at_substr_oid);
940 ldap_memfree(at->at_syntax_oid);
944 LDAP_ATTRIBUTE_TYPE *
945 ldap_str2attributetype( char * s, int * code, char ** errp )
952 int seen_obsolete = 0;
954 int seen_equality = 0;
955 int seen_ordering = 0;
962 LDAP_ATTRIBUTE_TYPE * at;
966 *code = LDAP_SCHERR_EMPTY;
972 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
975 *code = LDAP_SCHERR_OUTOFMEM;
979 kind = get_token(&ss,&sval);
980 if ( kind != TK_LEFTPAREN ) {
981 *code = LDAP_SCHERR_NOLEFTPAREN;
987 at->at_oid = parse_numericoid(&ss,code);
996 * Beyond this point we will be liberal and accept the items
1000 kind = get_token(&ss,&sval);
1003 *code = LDAP_SCHERR_NORIGHTPAREN;
1010 if ( !strcmp(sval,"NAME") ) {
1012 *code = LDAP_SCHERR_DUPOPT;
1018 at->at_names = parse_qdescrs(&ss,code);
1019 if ( !at->at_names ) {
1020 if ( *code != LDAP_SCHERR_OUTOFMEM )
1021 *code = LDAP_SCHERR_BADNAME;
1026 } else if ( !strcmp(sval,"DESC") ) {
1028 *code = LDAP_SCHERR_DUPOPT;
1035 kind = get_token(&ss,&sval);
1036 if ( kind != TK_QDSTRING ) {
1037 *code = LDAP_SCHERR_UNEXPTOKEN;
1044 } else if ( !strcmp(sval,"OBSOLETE") ) {
1045 if ( seen_obsolete ) {
1046 *code = LDAP_SCHERR_DUPOPT;
1052 at->at_obsolete = LDAP_SCHEMA_YES;
1054 } else if ( !strcmp(sval,"SUP") ) {
1056 *code = LDAP_SCHERR_DUPOPT;
1062 at->at_sup_oid = parse_woid(&ss,code);
1063 if ( !at->at_sup_oid ) {
1068 } else if ( !strcmp(sval,"EQUALITY") ) {
1069 if ( seen_equality ) {
1070 *code = LDAP_SCHERR_DUPOPT;
1076 at->at_equality_oid = parse_woid(&ss,code);
1077 if ( !at->at_equality_oid ) {
1082 } else if ( !strcmp(sval,"ORDERING") ) {
1083 if ( seen_ordering ) {
1084 *code = LDAP_SCHERR_DUPOPT;
1090 at->at_ordering_oid = parse_woid(&ss,code);
1091 if ( !at->at_ordering_oid ) {
1096 } else if ( !strcmp(sval,"SUBSTR") ) {
1097 if ( seen_substr ) {
1098 *code = LDAP_SCHERR_DUPOPT;
1104 at->at_substr_oid = parse_woid(&ss,code);
1105 if ( !at->at_substr_oid ) {
1110 } else if ( !strcmp(sval,"SYNTAX") ) {
1111 if ( seen_syntax ) {
1112 *code = LDAP_SCHERR_DUPOPT;
1119 at->at_syntax_oid = parse_noidlen(&ss,code,&at->at_syntax_len);
1120 if ( !at->at_syntax_oid ) {
1126 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1127 if ( at->at_single_value ) {
1128 *code = LDAP_SCHERR_DUPOPT;
1133 at->at_single_value = LDAP_SCHEMA_YES;
1135 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1136 if ( at->at_collective ) {
1137 *code = LDAP_SCHERR_DUPOPT;
1142 at->at_collective = LDAP_SCHEMA_YES;
1144 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1145 if ( at->at_no_user_mod ) {
1146 *code = LDAP_SCHERR_DUPOPT;
1151 at->at_no_user_mod = LDAP_SCHEMA_YES;
1153 } else if ( !strcmp(sval,"USAGE") ) {
1155 *code = LDAP_SCHERR_DUPOPT;
1162 kind = get_token(&ss,&sval);
1163 if ( kind != TK_BAREWORD ) {
1164 *code = LDAP_SCHERR_UNEXPTOKEN;
1169 if ( !strcasecmp(sval,"userApplications") )
1171 LDAP_SCHEMA_USER_APPLICATIONS;
1172 else if ( !strcasecmp(sval,"directoryOperation") )
1174 LDAP_SCHEMA_DIRECTORY_OPERATION;
1175 else if ( !strcasecmp(sval,"distributedOperation") )
1177 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1178 else if ( !strcasecmp(sval,"dSAOperation") )
1180 LDAP_SCHEMA_DSA_OPERATION;
1182 *code = LDAP_SCHERR_UNEXPTOKEN;
1188 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1189 /* Should be parse_qdstrings */
1190 ssdummy = parse_qdescrs(&ss, code);
1197 *code = LDAP_SCHERR_UNEXPTOKEN;
1204 *code = LDAP_SCHERR_UNEXPTOKEN;
1213 free_oc(LDAP_OBJECT_CLASS * oc)
1215 ldap_memfree(oc->oc_oid);
1216 charray_free(oc->oc_names);
1217 ldap_memfree(oc->oc_desc);
1218 charray_free(oc->oc_sup_oids);
1219 charray_free(oc->oc_at_oids_must);
1220 charray_free(oc->oc_at_oids_may);
1225 ldap_str2objectclass( char * s, int * code, char ** errp )
1232 int seen_obsolete = 0;
1237 LDAP_OBJECT_CLASS * oc;
1241 *code = LDAP_SCHERR_EMPTY;
1247 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1250 *code = LDAP_SCHERR_OUTOFMEM;
1254 kind = get_token(&ss,&sval);
1255 if ( kind != TK_LEFTPAREN ) {
1256 *code = LDAP_SCHERR_NOLEFTPAREN;
1262 oc->oc_oid = parse_numericoid(&ss,code);
1263 if ( !oc->oc_oid ) {
1271 * Beyond this point we will be liberal an accept the items
1275 kind = get_token(&ss,&sval);
1278 *code = LDAP_SCHERR_NORIGHTPAREN;
1285 if ( !strcmp(sval,"NAME") ) {
1287 *code = LDAP_SCHERR_DUPOPT;
1293 oc->oc_names = parse_qdescrs(&ss,code);
1294 if ( !oc->oc_names ) {
1295 if ( *code != LDAP_SCHERR_OUTOFMEM )
1296 *code = LDAP_SCHERR_BADNAME;
1301 } else if ( !strcmp(sval,"DESC") ) {
1303 *code = LDAP_SCHERR_DUPOPT;
1310 kind = get_token(&ss,&sval);
1311 if ( kind != TK_QDSTRING ) {
1312 *code = LDAP_SCHERR_UNEXPTOKEN;
1319 } else if ( !strcmp(sval,"OBSOLETE") ) {
1320 if ( seen_obsolete ) {
1321 *code = LDAP_SCHERR_DUPOPT;
1327 oc->oc_obsolete = LDAP_SCHEMA_YES;
1329 } else if ( !strcmp(sval,"SUP") ) {
1331 *code = LDAP_SCHERR_DUPOPT;
1337 oc->oc_sup_oids = parse_oids(&ss,code);
1338 if ( !oc->oc_sup_oids ) {
1343 } else if ( !strcmp(sval,"ABSTRACT") ) {
1345 *code = LDAP_SCHERR_DUPOPT;
1351 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1353 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1355 *code = LDAP_SCHERR_DUPOPT;
1361 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1363 } else if ( !strcmp(sval,"AUXILIARY") ) {
1365 *code = LDAP_SCHERR_DUPOPT;
1371 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1373 } else if ( !strcmp(sval,"MUST") ) {
1375 *code = LDAP_SCHERR_DUPOPT;
1381 oc->oc_at_oids_must = parse_oids(&ss,code);
1382 if ( !oc->oc_at_oids_must ) {
1388 } else if ( !strcmp(sval,"MAY") ) {
1390 *code = LDAP_SCHERR_DUPOPT;
1396 oc->oc_at_oids_may = parse_oids(&ss,code);
1397 if ( !oc->oc_at_oids_may ) {
1403 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1404 /* Should be parse_qdstrings */
1405 ssdummy = parse_qdescrs(&ss, code);
1412 *code = LDAP_SCHERR_UNEXPTOKEN;
1419 *code = LDAP_SCHERR_UNEXPTOKEN;
1427 static char *err2text[] = {
1431 "Missing opening parenthesis",
1432 "Missing closing parenthesis",
1438 "Unexpected end of data"
1442 ldap_scherr2str(int code)
1444 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1445 return "Unknown error";
1447 return err2text[code];