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
12 #include <ac/stdlib.h>
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));
46 ss->val = LDAP_MALLOC(size);
60 safe_string_free(safe_string * ss)
69 safe_string_val(safe_string * ss)
71 ss->val[ss->pos] = '\0';
76 append_to_safe_string(safe_string * ss, char * s)
82 * Some runaway process is trying to append to a string that
83 * overflowed and we could not extend.
88 /* We always make sure there is at least one position available */
89 if ( ss->pos + l >= ss->size-1 ) {
91 temp = LDAP_REALLOC(ss->val, ss->size);
93 /* Trouble, out of memory */
99 strncpy(&ss->val[ss->pos], s, l);
101 if ( ss->pos > 0 && ss->val[ss->pos-1] == ' ' )
110 print_literal(safe_string *ss, char *s)
112 return(append_to_safe_string(ss,s));
116 print_whsp(safe_string *ss)
119 return(append_to_safe_string(ss,""));
121 return(append_to_safe_string(ss," "));
125 print_numericoid(safe_string *ss, char *s)
128 return(append_to_safe_string(ss,s));
131 /* This one is identical to print_qdescr */
133 print_qdstring(safe_string *ss, char *s)
136 print_literal(ss,"'");
137 append_to_safe_string(ss,s);
138 print_literal(ss,"'");
139 return(print_whsp(ss));
143 print_qdescr(safe_string *ss, char *s)
146 print_literal(ss,"'");
147 append_to_safe_string(ss,s);
148 print_literal(ss,"'");
149 return(print_whsp(ss));
153 print_qdescrlist(safe_string *ss, char **sa)
158 for (sp=sa; *sp; sp++) {
159 ret = print_qdescr(ss,*sp);
161 /* If the list was empty, we return zero that is potentially
162 * incorrect, but since we will be still appending things, the
163 * overflow will be detected later. Maybe FIX.
169 print_qdescrs(safe_string *ss, char **sa)
171 /* The only way to represent an empty list is as a qdescrlist
172 * so, if the list is empty we treat it as a long list.
173 * Really, this is what the syntax mandates. We should not
174 * be here if the list was empty, but if it happens, a label
175 * has already been output and we cannot undo it.
177 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
179 print_literal(ss,"(");
180 print_qdescrlist(ss,sa);
181 print_literal(ss,")");
182 return(print_whsp(ss));
184 return(print_qdescr(ss,*sa));
189 print_woid(safe_string *ss, char *s)
192 append_to_safe_string(ss,s);
193 return print_whsp(ss);
197 print_oidlist(safe_string *ss, char **sa)
201 for (sp=sa; *(sp+1); sp++) {
203 print_literal(ss,"$");
205 return(print_woid(ss,*sp));
209 print_oids(safe_string *ss, char **sa)
211 if ( sa[0] && sa[1] ) {
212 print_literal(ss,"(");
213 print_oidlist(ss,sa);
215 return(print_literal(ss,")"));
217 return(print_woid(ss,*sa));
222 print_noidlen(safe_string *ss, char *s, int l)
227 ret = print_numericoid(ss,s);
229 sprintf(buf,"{%d}",l);
230 ret = print_literal(ss,buf);
236 ldap_syntax2str( LDAP_SYNTAX * syn )
241 ss = new_safe_string(256);
245 print_literal(ss,"(");
248 print_numericoid(ss, syn->syn_oid);
251 if ( syn->syn_desc ) {
252 print_literal(ss,"DESC");
253 print_qdstring(ss,syn->syn_desc);
257 print_literal(ss,")");
259 retstring = LDAP_STRDUP(safe_string_val(ss));
260 safe_string_free(ss);
265 ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
270 ss = new_safe_string(256);
274 print_literal(ss,"(");
277 print_numericoid(ss, oc->oc_oid);
280 if ( oc->oc_names ) {
281 print_literal(ss,"NAME");
282 print_qdescrs(ss,oc->oc_names);
286 print_literal(ss,"DESC");
287 print_qdstring(ss,oc->oc_desc);
290 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
291 print_literal(ss, "OBSOLETE");
295 if ( oc->oc_sup_oids ) {
296 print_literal(ss,"SUP");
297 print_oids(ss,oc->oc_sup_oids);
300 switch (oc->oc_kind) {
301 case LDAP_SCHEMA_ABSTRACT:
302 print_literal(ss,"ABSTRACT");
304 case LDAP_SCHEMA_STRUCTURAL:
305 print_literal(ss,"STRUCTURAL");
307 case LDAP_SCHEMA_AUXILIARY:
308 print_literal(ss,"AUXILIARY");
311 print_literal(ss,"KIND-UNKNOWN");
316 if ( oc->oc_at_oids_must ) {
317 print_literal(ss,"MUST");
319 print_oids(ss,oc->oc_at_oids_must);
323 if ( oc->oc_at_oids_may ) {
324 print_literal(ss,"MAY");
326 print_oids(ss,oc->oc_at_oids_may);
331 print_literal(ss,")");
333 retstring = LDAP_STRDUP(safe_string_val(ss));
334 safe_string_free(ss);
339 ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
344 ss = new_safe_string(256);
348 print_literal(ss,"(");
351 print_numericoid(ss, at->at_oid);
354 if ( at->at_names ) {
355 print_literal(ss,"NAME");
356 print_qdescrs(ss,at->at_names);
360 print_literal(ss,"DESC");
361 print_qdstring(ss,at->at_desc);
364 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
365 print_literal(ss, "OBSOLETE");
369 if ( at->at_sup_oid ) {
370 print_literal(ss,"SUP");
371 print_woid(ss,at->at_sup_oid);
374 if ( at->at_equality_oid ) {
375 print_literal(ss,"EQUALITY");
376 print_woid(ss,at->at_equality_oid);
379 if ( at->at_ordering_oid ) {
380 print_literal(ss,"ORDERING");
381 print_woid(ss,at->at_ordering_oid);
384 if ( at->at_substr_oid ) {
385 print_literal(ss,"SUBSTR");
386 print_woid(ss,at->at_substr_oid);
389 if ( at->at_syntax_oid ) {
390 print_literal(ss,"SYNTAX");
392 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
395 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
396 print_literal(ss,"SINGLE-VALUE");
400 if ( at->at_collective == LDAP_SCHEMA_YES ) {
401 print_literal(ss,"COLLECTIVE");
405 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
406 print_literal(ss,"NO-USER-MODIFICATION");
410 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
411 print_literal(ss,"USAGE");
413 switch (at->at_usage) {
414 case LDAP_SCHEMA_DIRECTORY_OPERATION:
415 print_literal(ss,"directoryOperation");
417 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
418 print_literal(ss,"distributedOperation");
420 case LDAP_SCHEMA_DSA_OPERATION:
421 print_literal(ss,"dSAOperation");
424 print_literal(ss,"UNKNOWN");
430 print_literal(ss,")");
432 retstring = LDAP_STRDUP(safe_string_val(ss));
433 safe_string_free(ss);
438 * Now come the parsers. There is one parser for each entity type:
439 * objectclasses, attributetypes, etc.
441 * Each of them is written as a recursive-descent parser, except that
442 * none of them is really recursive. But the idea is kept: there
443 * is one routine per non-terminal that eithers gobbles lexical tokens
444 * or calls lower-level routines, etc.
446 * The scanner is implemented in the routine get_token. Actually,
447 * get_token is more than a scanner and will return tokens that are
448 * in fact non-terminals in the grammar. So you can see the whole
449 * approach as the combination of a low-level bottom-up recognizer
450 * combined with a scanner and a number of top-down parsers. Or just
451 * consider that the real grammars recognized by the parsers are not
452 * those of the standards. As a matter of fact, our parsers are more
453 * liberal than the spec when there is no ambiguity.
455 * The difference is pretty academic (modulo bugs or incorrect
456 * interpretation of the specs).
459 #define TK_NOENDQUOTE -2
460 #define TK_OUTOFMEM -1
462 #define TK_UNEXPCHAR 1
463 #define TK_BAREWORD 2
464 #define TK_QDSTRING 3
465 #define TK_LEFTPAREN 4
466 #define TK_RIGHTPAREN 5
468 #define TK_QDESCR TK_QDSTRING
476 get_token(char ** sp, char ** token_val)
493 kind = TK_RIGHTPAREN;
504 while ( **sp != '\'' && **sp != '\0' )
506 if ( **sp == '\'' ) {
508 res = LDAP_MALLOC(q-p+1);
518 kind = TK_NOENDQUOTE;
524 while ( !isspace(**sp) && **sp != '\0' )
527 res = LDAP_MALLOC(q-p+1);
536 /* kind = TK_UNEXPCHAR; */
543 /* Gobble optional whitespace */
545 parse_whsp(char **sp)
547 while (isspace(**sp))
552 * General note for all parsers: to guarantee the algorithm halts they
553 * must always advance the pointer even when an error is found. For
554 * this one is not that important since an error here is fatal at the
555 * upper layers, but it is a simple strategy that will not get in
559 /* Parse a sequence of dot-separated decimal strings */
561 parse_numericoid(char **sp, int *code)
567 /* Each iteration of this loops gets one decimal string */
569 if ( !isdigit(**sp) ) {
571 * Initial char is not a digit or char after dot is
574 *code = LDAP_SCHERR_NODIGIT;
578 while ( isdigit(**sp) )
582 /* Otherwise, gobble the dot and loop again */
585 /* Now *sp points at the char past the numericoid. Perfect. */
587 res = LDAP_MALLOC(len+1);
589 *code = LDAP_SCHERR_OUTOFMEM;
592 strncpy(res,start,len);
597 /* Parse a qdescr or a list of them enclosed in () */
599 parse_qdescrs(char **sp, int *code)
609 kind = get_token(sp,&sval);
610 if ( kind == TK_LEFTPAREN ) {
611 /* Let's presume there will be at least 2 entries */
613 res = LDAP_CALLOC(3,sizeof(char *));
615 *code = LDAP_SCHERR_OUTOFMEM;
621 kind = get_token(sp,&sval);
622 if ( kind == TK_RIGHTPAREN )
624 if ( kind == TK_QDESCR ) {
625 if ( pos == size-2 ) {
627 res1 = LDAP_REALLOC(res,size*sizeof(char *));
630 *code = LDAP_SCHERR_OUTOFMEM;
640 *code = LDAP_SCHERR_UNEXPTOKEN;
647 } else if ( kind == TK_QDESCR ) {
648 res = LDAP_CALLOC(2,sizeof(char *));
650 *code = LDAP_SCHERR_OUTOFMEM;
658 *code = LDAP_SCHERR_BADNAME;
665 parse_woid(char **sp, int *code)
671 kind = get_token(sp, &sval);
672 if ( kind != TK_BAREWORD ) {
673 *code = LDAP_SCHERR_UNEXPTOKEN;
680 /* Parse a noidlen */
682 parse_noidlen(char **sp, int *code, int *len)
688 kind = get_token(sp, &sval);
689 if ( kind != TK_BAREWORD ) {
690 *code = LDAP_SCHERR_UNEXPTOKEN;
696 while ( isdigit(**sp) )
700 *code = LDAP_SCHERR_UNEXPTOKEN;
710 * Next routine will accept a qdstring in place of an oid. This is
711 * necessary to interoperate with Netscape Directory server that
712 * will improperly quote each oid (at least those of the descr kind)
716 /* Parse a woid or a $-separated list of them enclosed in () */
718 parse_oids(char **sp, int *code)
728 * Strictly speaking, doing this here accepts whsp before the
729 * ( at the begining of an oidlist, but his is harmless. Also,
730 * we are very liberal in what we accept as an OID. Maybe
734 kind = get_token(sp,&sval);
735 if ( kind == TK_LEFTPAREN ) {
736 /* Let's presume there will be at least 2 entries */
738 res = LDAP_CALLOC(3,sizeof(char *));
740 *code = LDAP_SCHERR_OUTOFMEM;
745 kind = get_token(sp,&sval);
746 if ( kind == TK_BAREWORD || kind == TK_QDSTRING ) {
750 *code = LDAP_SCHERR_UNEXPTOKEN;
756 kind = get_token(sp,&sval);
757 if ( kind == TK_RIGHTPAREN )
759 if ( kind == TK_DOLLAR ) {
761 kind = get_token(sp,&sval);
762 if ( kind == TK_BAREWORD ||
763 kind == TK_QDSTRING ) {
764 if ( pos == size-2 ) {
766 res1 = LDAP_REALLOC(res,size*sizeof(char *));
769 *code = LDAP_SCHERR_OUTOFMEM;
777 *code = LDAP_SCHERR_UNEXPTOKEN;
783 *code = LDAP_SCHERR_UNEXPTOKEN;
791 } else if ( kind == TK_BAREWORD || kind == TK_QDSTRING ) {
792 res = LDAP_CALLOC(2,sizeof(char *));
794 *code = LDAP_SCHERR_OUTOFMEM;
802 *code = LDAP_SCHERR_BADNAME;
808 free_syn(LDAP_SYNTAX * syn)
810 LDAP_FREE(syn->syn_oid);
811 LDAP_FREE(syn->syn_desc);
816 ldap_str2syntax( char * s, int * code, char ** errp )
826 *code = LDAP_SCHERR_EMPTY;
832 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
835 *code = LDAP_SCHERR_OUTOFMEM;
839 kind = get_token(&ss,&sval);
840 if ( kind != TK_LEFTPAREN ) {
841 *code = LDAP_SCHERR_NOLEFTPAREN;
847 syn->syn_oid = parse_numericoid(&ss,code);
848 if ( !syn->syn_oid ) {
856 * Beyond this point we will be liberal and accept the items
860 kind = get_token(&ss,&sval);
863 *code = LDAP_SCHERR_NORIGHTPAREN;
870 if ( !strcmp(sval,"DESC") ) {
872 *code = LDAP_SCHERR_DUPOPT;
879 kind = get_token(&ss,&sval);
880 if ( kind != TK_QDSTRING ) {
881 *code = LDAP_SCHERR_UNEXPTOKEN;
886 syn->syn_desc = sval;
888 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
889 /* Should be parse_qdstrings */
890 ssdummy = parse_qdescrs(&ss, code);
897 *code = LDAP_SCHERR_UNEXPTOKEN;
904 *code = LDAP_SCHERR_UNEXPTOKEN;
913 free_at(LDAP_ATTRIBUTE_TYPE * at)
915 LDAP_FREE(at->at_oid);
916 LDAP_VFREE(at->at_names);
917 LDAP_FREE(at->at_desc);
918 LDAP_FREE(at->at_sup_oid);
919 LDAP_FREE(at->at_equality_oid);
920 LDAP_FREE(at->at_ordering_oid);
921 LDAP_FREE(at->at_substr_oid);
922 LDAP_FREE(at->at_syntax_oid);
926 LDAP_ATTRIBUTE_TYPE *
927 ldap_str2attributetype( char * s, int * code, char ** errp )
934 int seen_obsolete = 0;
936 int seen_equality = 0;
937 int seen_ordering = 0;
944 LDAP_ATTRIBUTE_TYPE * at;
948 *code = LDAP_SCHERR_EMPTY;
954 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
957 *code = LDAP_SCHERR_OUTOFMEM;
961 kind = get_token(&ss,&sval);
962 if ( kind != TK_LEFTPAREN ) {
963 *code = LDAP_SCHERR_NOLEFTPAREN;
969 at->at_oid = parse_numericoid(&ss,code);
978 * Beyond this point we will be liberal and accept the items
982 kind = get_token(&ss,&sval);
985 *code = LDAP_SCHERR_NORIGHTPAREN;
992 if ( !strcmp(sval,"NAME") ) {
994 *code = LDAP_SCHERR_DUPOPT;
1000 at->at_names = parse_qdescrs(&ss,code);
1001 if ( !at->at_names ) {
1002 if ( *code != LDAP_SCHERR_OUTOFMEM )
1003 *code = LDAP_SCHERR_BADNAME;
1008 } else if ( !strcmp(sval,"DESC") ) {
1010 *code = LDAP_SCHERR_DUPOPT;
1017 kind = get_token(&ss,&sval);
1018 if ( kind != TK_QDSTRING ) {
1019 *code = LDAP_SCHERR_UNEXPTOKEN;
1026 } else if ( !strcmp(sval,"OBSOLETE") ) {
1027 if ( seen_obsolete ) {
1028 *code = LDAP_SCHERR_DUPOPT;
1034 at->at_obsolete = LDAP_SCHEMA_YES;
1036 } else if ( !strcmp(sval,"SUP") ) {
1038 *code = LDAP_SCHERR_DUPOPT;
1044 at->at_sup_oid = parse_woid(&ss,code);
1045 if ( !at->at_sup_oid ) {
1050 } else if ( !strcmp(sval,"EQUALITY") ) {
1051 if ( seen_equality ) {
1052 *code = LDAP_SCHERR_DUPOPT;
1058 at->at_equality_oid = parse_woid(&ss,code);
1059 if ( !at->at_equality_oid ) {
1064 } else if ( !strcmp(sval,"ORDERING") ) {
1065 if ( seen_ordering ) {
1066 *code = LDAP_SCHERR_DUPOPT;
1072 at->at_ordering_oid = parse_woid(&ss,code);
1073 if ( !at->at_ordering_oid ) {
1078 } else if ( !strcmp(sval,"SUBSTR") ) {
1079 if ( seen_substr ) {
1080 *code = LDAP_SCHERR_DUPOPT;
1086 at->at_substr_oid = parse_woid(&ss,code);
1087 if ( !at->at_substr_oid ) {
1092 } else if ( !strcmp(sval,"SYNTAX") ) {
1093 if ( seen_syntax ) {
1094 *code = LDAP_SCHERR_DUPOPT;
1101 at->at_syntax_oid = parse_noidlen(&ss,code,&at->at_syntax_len);
1102 if ( !at->at_syntax_oid ) {
1108 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1109 if ( at->at_single_value ) {
1110 *code = LDAP_SCHERR_DUPOPT;
1115 at->at_single_value = LDAP_SCHEMA_YES;
1117 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1118 if ( at->at_collective ) {
1119 *code = LDAP_SCHERR_DUPOPT;
1124 at->at_collective = LDAP_SCHEMA_YES;
1126 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1127 if ( at->at_no_user_mod ) {
1128 *code = LDAP_SCHERR_DUPOPT;
1133 at->at_no_user_mod = LDAP_SCHEMA_YES;
1135 } else if ( !strcmp(sval,"USAGE") ) {
1137 *code = LDAP_SCHERR_DUPOPT;
1144 kind = get_token(&ss,&sval);
1145 if ( kind != TK_BAREWORD ) {
1146 *code = LDAP_SCHERR_UNEXPTOKEN;
1151 if ( !strcasecmp(sval,"userApplications") )
1153 LDAP_SCHEMA_USER_APPLICATIONS;
1154 else if ( !strcasecmp(sval,"directoryOperation") )
1156 LDAP_SCHEMA_DIRECTORY_OPERATION;
1157 else if ( !strcasecmp(sval,"distributedOperation") )
1159 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1160 else if ( !strcasecmp(sval,"dSAOperation") )
1162 LDAP_SCHEMA_DSA_OPERATION;
1164 *code = LDAP_SCHERR_UNEXPTOKEN;
1170 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1171 /* Should be parse_qdstrings */
1172 ssdummy = parse_qdescrs(&ss, code);
1179 *code = LDAP_SCHERR_UNEXPTOKEN;
1186 *code = LDAP_SCHERR_UNEXPTOKEN;
1195 free_oc(LDAP_OBJECT_CLASS * oc)
1197 LDAP_FREE(oc->oc_oid);
1198 LDAP_VFREE(oc->oc_names);
1199 LDAP_FREE(oc->oc_desc);
1200 LDAP_VFREE(oc->oc_sup_oids);
1201 LDAP_VFREE(oc->oc_at_oids_must);
1202 LDAP_VFREE(oc->oc_at_oids_may);
1207 ldap_str2objectclass( char * s, int * code, char ** errp )
1214 int seen_obsolete = 0;
1219 LDAP_OBJECT_CLASS * oc;
1223 *code = LDAP_SCHERR_EMPTY;
1229 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1232 *code = LDAP_SCHERR_OUTOFMEM;
1236 kind = get_token(&ss,&sval);
1237 if ( kind != TK_LEFTPAREN ) {
1238 *code = LDAP_SCHERR_NOLEFTPAREN;
1244 oc->oc_oid = parse_numericoid(&ss,code);
1245 if ( !oc->oc_oid ) {
1253 * Beyond this point we will be liberal an accept the items
1257 kind = get_token(&ss,&sval);
1260 *code = LDAP_SCHERR_NORIGHTPAREN;
1267 if ( !strcmp(sval,"NAME") ) {
1269 *code = LDAP_SCHERR_DUPOPT;
1275 oc->oc_names = parse_qdescrs(&ss,code);
1276 if ( !oc->oc_names ) {
1277 if ( *code != LDAP_SCHERR_OUTOFMEM )
1278 *code = LDAP_SCHERR_BADNAME;
1283 } else if ( !strcmp(sval,"DESC") ) {
1285 *code = LDAP_SCHERR_DUPOPT;
1292 kind = get_token(&ss,&sval);
1293 if ( kind != TK_QDSTRING ) {
1294 *code = LDAP_SCHERR_UNEXPTOKEN;
1301 } else if ( !strcmp(sval,"OBSOLETE") ) {
1302 if ( seen_obsolete ) {
1303 *code = LDAP_SCHERR_DUPOPT;
1309 oc->oc_obsolete = LDAP_SCHEMA_YES;
1311 } else if ( !strcmp(sval,"SUP") ) {
1313 *code = LDAP_SCHERR_DUPOPT;
1319 oc->oc_sup_oids = parse_oids(&ss,code);
1320 if ( !oc->oc_sup_oids ) {
1325 } else if ( !strcmp(sval,"ABSTRACT") ) {
1327 *code = LDAP_SCHERR_DUPOPT;
1333 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1335 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1337 *code = LDAP_SCHERR_DUPOPT;
1343 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1345 } else if ( !strcmp(sval,"AUXILIARY") ) {
1347 *code = LDAP_SCHERR_DUPOPT;
1353 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1355 } else if ( !strcmp(sval,"MUST") ) {
1357 *code = LDAP_SCHERR_DUPOPT;
1363 oc->oc_at_oids_must = parse_oids(&ss,code);
1364 if ( !oc->oc_at_oids_must ) {
1370 } else if ( !strcmp(sval,"MAY") ) {
1372 *code = LDAP_SCHERR_DUPOPT;
1378 oc->oc_at_oids_may = parse_oids(&ss,code);
1379 if ( !oc->oc_at_oids_may ) {
1385 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1386 /* Should be parse_qdstrings */
1387 ssdummy = parse_qdescrs(&ss, code);
1394 *code = LDAP_SCHERR_UNEXPTOKEN;
1401 *code = LDAP_SCHERR_UNEXPTOKEN;
1409 static char *err2text[] = {
1413 "Missing opening parenthesis",
1414 "Missing closing parenthesis",
1420 "Unexpected end of data"
1424 ldap_scherr2str(int code)
1426 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1427 return "Unknown error";
1429 return err2text[code];