libs: Import code from upstream openldap 2.5.13.
[wine.git] / libs / ldap / libldap / ldif.c
blobbf75dd0b013323b33c0a84cdf8b32f9b8f2e7e2c
1 /* ldif.c - routines for dealing with LDIF files */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the
22 * University may not be used to endorse or promote products derived
23 * from this software without specific prior written permission. This
24 * software is provided ``as is'' without express or implied warranty.
26 /* This work was originally developed by the University of Michigan
27 * and distributed as part of U-MICH LDAP.
30 #include "portable.h"
32 #include <stdio.h>
34 #include <ac/stdlib.h>
35 #include <ac/ctype.h>
37 #include <ac/string.h>
38 #include <ac/socket.h>
39 #include <ac/time.h>
41 int ldif_debug = 0;
43 #include "ldap-int.h"
44 #include "ldif.h"
46 #define CONTINUED_LINE_MARKER '\r'
48 #ifdef CSRIMALLOC
49 #define ber_memalloc malloc
50 #define ber_memcalloc calloc
51 #define ber_memrealloc realloc
52 #define ber_strdup strdup
53 #endif
55 static const char nib2b64[0x40] =
56 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
59 * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
60 * into components "type" and "value". if a double colon separates type from
61 * value, then value is encoded in base 64, and parse_line un-decodes it
62 * (in place) before returning. The type and value are stored in malloc'd
63 * memory which must be freed by the caller.
65 * ldif_parse_line2 - operates in-place on input buffer, returning type
66 * in-place. Will return value in-place if possible, (must malloc for
67 * fetched URLs). If freeval is NULL, all return data will be malloc'd
68 * and the input line will be unmodified. Otherwise freeval is set to
69 * True if the value was malloc'd.
72 int
73 ldif_parse_line(
74 LDAP_CONST char *line,
75 char **typep,
76 char **valuep,
77 ber_len_t *vlenp
80 struct berval type, value;
81 int rc = ldif_parse_line2( (char *)line, &type, &value, NULL );
83 *typep = type.bv_val;
84 *valuep = value.bv_val;
85 *vlenp = value.bv_len;
86 return rc;
89 int
90 ldif_parse_line2(
91 char *line,
92 struct berval *type,
93 struct berval *value,
94 int *freeval
97 char *s, *p, *d;
98 int b64, url;
100 BER_BVZERO( type );
101 BER_BVZERO( value );
103 /* skip any leading space */
104 while ( isspace( (unsigned char) *line ) ) {
105 line++;
108 if ( freeval ) {
109 *freeval = 0;
110 } else {
111 line = ber_strdup( line );
113 if( line == NULL ) {
114 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
115 _("ldif_parse_line: line malloc failed\n"));
116 return( -1 );
120 type->bv_val = line;
122 s = strchr( type->bv_val, ':' );
124 if ( s == NULL ) {
125 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
126 _("ldif_parse_line: missing ':' after %s\n"),
127 type->bv_val );
128 if ( !freeval ) ber_memfree( line );
129 return( -1 );
132 /* trim any space between type and : */
133 for ( p = &s[-1]; p > type->bv_val && isspace( * (unsigned char *) p ); p-- ) {
134 *p = '\0';
136 *s++ = '\0';
137 type->bv_len = s - type->bv_val - 1;
139 url = 0;
140 b64 = 0;
142 if ( *s == '<' ) {
143 s++;
144 url = 1;
146 } else if ( *s == ':' ) {
147 /* base 64 encoded value */
148 s++;
149 b64 = 1;
152 /* skip space between : and value */
153 while ( isspace( (unsigned char) *s ) ) {
154 s++;
157 /* check for continued line markers that should be deleted */
158 for ( p = s, d = s; *p; p++ ) {
159 if ( *p != CONTINUED_LINE_MARKER )
160 *d++ = *p;
162 *d = '\0';
164 if ( b64 ) {
165 char *byte = s;
167 if ( *s == '\0' ) {
168 /* no value is present, error out */
169 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
170 _("ldif_parse_line: %s missing base64 value\n"),
171 type->bv_val );
172 if ( !freeval ) ber_memfree( line );
173 return( -1 );
176 value->bv_val = s;
177 value->bv_len = d - s;
178 if ( ldap_int_decode_b64_inplace( value ) != LDAP_SUCCESS ) {
179 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
180 _("ldif_parse_line: %s base64 decode failed\n"),
181 type->bv_val );
182 if ( !freeval ) ber_memfree( line );
183 return( -1 );
185 } else if ( url ) {
186 if ( *s == '\0' ) {
187 /* no value is present, error out */
188 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
189 _("ldif_parse_line: %s missing URL value\n"),
190 type->bv_val );
191 if ( !freeval ) ber_memfree( line );
192 return( -1 );
195 if( ldif_fetch_url( s, &value->bv_val, &value->bv_len ) ) {
196 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
197 _("ldif_parse_line: %s: URL \"%s\" fetch failed\n"),
198 type->bv_val, s );
199 if ( !freeval ) ber_memfree( line );
200 return( -1 );
202 if ( freeval ) *freeval = 1;
204 } else {
205 value->bv_val = s;
206 value->bv_len = (int) (d - s);
209 if ( !freeval ) {
210 struct berval bv = *type;
212 ber_dupbv( type, &bv );
214 if( BER_BVISNULL( type )) {
215 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
216 _("ldif_parse_line: type malloc failed\n"));
217 if( url ) ber_memfree( value->bv_val );
218 ber_memfree( line );
219 return( -1 );
222 if( !url ) {
223 bv = *value;
224 ber_dupbv( value, &bv );
225 if( BER_BVISNULL( value )) {
226 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
227 _("ldif_parse_line: value malloc failed\n"));
228 ber_memfree( type->bv_val );
229 ber_memfree( line );
230 return( -1 );
234 ber_memfree( line );
237 return( 0 );
241 * ldif_getline - return the next "line" (minus newline) of input from a
242 * string buffer of lines separated by newlines, terminated by \n\n
243 * or \0. this routine handles continued lines, bundling them into
244 * a single big line before returning. if a line begins with a white
245 * space character, it is a continuation of the previous line. the white
246 * space character (nb: only one char), and preceding newline are changed
247 * into CONTINUED_LINE_MARKER chars, to be deleted later by the
248 * ldif_parse_line() routine above.
250 * ldif_getline will skip over any line which starts '#'.
252 * ldif_getline takes a pointer to a pointer to the buffer on the first call,
253 * which it updates and must be supplied on subsequent calls.
257 ldif_countlines( LDAP_CONST char *buf )
259 char *nl;
260 int ret = 0;
262 if ( !buf ) return ret;
264 for ( nl = strchr(buf, '\n'); nl; nl = strchr(nl, '\n') ) {
265 nl++;
266 if ( *nl != ' ' ) ret++;
268 return ret;
271 char *
272 ldif_getline( char **next )
274 char *line;
276 do {
277 if ( *next == NULL || **next == '\n' || **next == '\0' ) {
278 return( NULL );
281 line = *next;
283 while ( (*next = strchr( *next, '\n' )) != NULL ) {
284 #if CONTINUED_LINE_MARKER != '\r'
285 if ( (*next)[-1] == '\r' ) {
286 (*next)[-1] = CONTINUED_LINE_MARKER;
288 #endif
290 if ( (*next)[1] != ' ' ) {
291 if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) {
292 *(*next)++ = '\0';
294 *(*next)++ = '\0';
295 break;
298 **next = CONTINUED_LINE_MARKER;
299 (*next)[1] = CONTINUED_LINE_MARKER;
300 (*next)++;
302 } while( *line == '#' );
304 return( line );
308 * name and OID of attributeTypes that must be base64 encoded in any case
310 typedef struct must_b64_encode_s {
311 struct berval name;
312 struct berval oid;
313 } must_b64_encode_s;
315 static must_b64_encode_s default_must_b64_encode[] = {
316 { BER_BVC( "userPassword" ), BER_BVC( "2.5.4.35" ) },
317 { BER_BVNULL, BER_BVNULL }
320 static must_b64_encode_s *must_b64_encode = default_must_b64_encode;
323 * register name and OID of attributeTypes that must always be base64
324 * encoded
326 * NOTE: this routine mallocs memory in a static struct which must
327 * be explicitly freed when no longer required
330 ldif_must_b64_encode_register( LDAP_CONST char *name, LDAP_CONST char *oid )
332 int i;
333 ber_len_t len;
335 assert( must_b64_encode != NULL );
336 assert( name != NULL );
337 assert( oid != NULL );
339 len = strlen( name );
341 for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
342 if ( len != must_b64_encode[i].name.bv_len ) {
343 continue;
346 if ( strcasecmp( name, must_b64_encode[i].name.bv_val ) == 0 ) {
347 break;
351 if ( !BER_BVISNULL( &must_b64_encode[i].name ) ) {
352 return 1;
355 for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ )
356 /* just count */ ;
358 if ( must_b64_encode == default_must_b64_encode ) {
359 must_b64_encode = ber_memalloc( sizeof( must_b64_encode_s ) * ( i + 2 ) );
360 if ( must_b64_encode == NULL ) {
361 return 1;
364 for ( i = 0; !BER_BVISNULL( &default_must_b64_encode[i].name ); i++ ) {
365 ber_dupbv( &must_b64_encode[i].name, &default_must_b64_encode[i].name );
366 ber_dupbv( &must_b64_encode[i].oid, &default_must_b64_encode[i].oid );
369 } else {
370 must_b64_encode_s *tmp;
372 tmp = ber_memrealloc( must_b64_encode,
373 sizeof( must_b64_encode_s ) * ( i + 2 ) );
374 if ( tmp == NULL ) {
375 return 1;
377 must_b64_encode = tmp;
380 ber_str2bv( name, len, 1, &must_b64_encode[i].name );
381 ber_str2bv( oid, 0, 1, &must_b64_encode[i].oid );
383 BER_BVZERO( &must_b64_encode[i + 1].name );
385 return 0;
388 void
389 ldif_must_b64_encode_release( void )
391 int i;
393 assert( must_b64_encode != NULL );
395 if ( must_b64_encode == default_must_b64_encode ) {
396 return;
399 for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
400 ber_memfree( must_b64_encode[i].name.bv_val );
401 ber_memfree( must_b64_encode[i].oid.bv_val );
404 ber_memfree( must_b64_encode );
406 must_b64_encode = default_must_b64_encode;
410 * returns 1 iff the string corresponds to the name or the OID of any
411 * of the attributeTypes listed in must_b64_encode
413 static int
414 ldif_must_b64_encode( LDAP_CONST char *s )
416 int i;
417 struct berval bv;
419 assert( must_b64_encode != NULL );
420 assert( s != NULL );
422 ber_str2bv( s, 0, 0, &bv );
424 for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
425 if ( ber_bvstrcasecmp( &must_b64_encode[i].name, &bv ) == 0
426 || ber_bvcmp( &must_b64_encode[i].oid, &bv ) == 0 )
428 return 1;
432 return 0;
435 /* NOTE: only preserved for binary compatibility */
436 void
437 ldif_sput(
438 char **out,
439 int type,
440 LDAP_CONST char *name,
441 LDAP_CONST char *val,
442 ber_len_t vlen )
444 ldif_sput_wrap( out, type, name, val, vlen, 0 );
447 void
448 ldif_sput_wrap(
449 char **out,
450 int type,
451 LDAP_CONST char *name,
452 LDAP_CONST char *val,
453 ber_len_t vlen,
454 ber_len_t wrap )
456 const unsigned char *byte, *stop;
457 unsigned char buf[3];
458 unsigned long bits;
459 char *save;
460 int pad;
461 int namelen = 0;
463 ber_len_t savelen;
464 ber_len_t len=0;
465 ber_len_t i;
467 if ( !wrap )
468 wrap = LDIF_LINE_WIDTH;
470 /* prefix */
471 switch( type ) {
472 case LDIF_PUT_COMMENT:
473 *(*out)++ = '#';
474 len++;
476 if( vlen ) {
477 *(*out)++ = ' ';
478 len++;
481 break;
483 case LDIF_PUT_SEP:
484 *(*out)++ = '\n';
485 return;
488 /* name (attribute type) */
489 if( name != NULL ) {
490 /* put the name + ":" */
491 namelen = strlen(name);
492 strcpy(*out, name);
493 *out += namelen;
494 len += namelen;
496 if( type != LDIF_PUT_COMMENT ) {
497 *(*out)++ = ':';
498 len++;
502 #ifdef LDAP_DEBUG
503 else {
504 assert( type == LDIF_PUT_COMMENT );
506 #endif
508 if( vlen == 0 ) {
509 *(*out)++ = '\n';
510 return;
513 switch( type ) {
514 case LDIF_PUT_NOVALUE:
515 *(*out)++ = '\n';
516 return;
518 case LDIF_PUT_URL: /* url value */
519 *(*out)++ = '<';
520 len++;
521 break;
523 case LDIF_PUT_B64: /* base64 value */
524 *(*out)++ = ':';
525 len++;
526 break;
529 switch( type ) {
530 case LDIF_PUT_TEXT:
531 case LDIF_PUT_URL:
532 case LDIF_PUT_B64:
533 *(*out)++ = ' ';
534 len++;
535 /* fall-thru */
537 case LDIF_PUT_COMMENT:
538 /* pre-encoded names */
539 for ( i=0; i < vlen; i++ ) {
540 if ( len > wrap ) {
541 *(*out)++ = '\n';
542 *(*out)++ = ' ';
543 len = 1;
546 *(*out)++ = val[i];
547 len++;
549 *(*out)++ = '\n';
550 return;
553 save = *out;
554 savelen = len;
556 *(*out)++ = ' ';
557 len++;
559 stop = (const unsigned char *) (val + vlen);
561 if ( type == LDIF_PUT_VALUE
562 && isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<'
563 && isgraph( (unsigned char) val[vlen-1] )
564 #ifndef LDAP_BINARY_DEBUG
565 && strstr( name, ";binary" ) == NULL
566 #endif
567 #ifndef LDAP_PASSWD_DEBUG
568 && !ldif_must_b64_encode( name )
569 #endif
571 int b64 = 0;
573 for ( byte = (const unsigned char *) val; byte < stop;
574 byte++, len++ )
576 if ( !isascii( *byte ) || !isprint( *byte ) ) {
577 b64 = 1;
578 break;
580 if ( len >= wrap ) {
581 *(*out)++ = '\n';
582 *(*out)++ = ' ';
583 len = 1;
585 *(*out)++ = *byte;
588 if( !b64 ) {
589 *(*out)++ = '\n';
590 return;
594 *out = save;
595 *(*out)++ = ':';
596 *(*out)++ = ' ';
597 len = savelen + 2;
599 /* convert to base 64 (3 bytes => 4 base 64 digits) */
600 for ( byte = (const unsigned char *) val;
601 byte < stop - 2;
602 byte += 3 )
604 bits = (byte[0] & 0xff) << 16;
605 bits |= (byte[1] & 0xff) << 8;
606 bits |= (byte[2] & 0xff);
608 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
609 if ( len >= wrap ) {
610 *(*out)++ = '\n';
611 *(*out)++ = ' ';
612 len = 1;
615 /* get b64 digit from high order 6 bits */
616 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
620 /* add padding if necessary */
621 if ( byte < stop ) {
622 for ( i = 0; byte + i < stop; i++ ) {
623 buf[i] = byte[i];
625 for ( pad = 0; i < 3; i++, pad++ ) {
626 buf[i] = '\0';
628 byte = buf;
629 bits = (byte[0] & 0xff) << 16;
630 bits |= (byte[1] & 0xff) << 8;
631 bits |= (byte[2] & 0xff);
633 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
634 if ( len >= wrap ) {
635 *(*out)++ = '\n';
636 *(*out)++ = ' ';
637 len = 1;
640 if( i + pad < 4 ) {
641 /* get b64 digit from low order 6 bits */
642 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
643 } else {
644 *(*out)++ = '=';
648 *(*out)++ = '\n';
653 * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
656 /* NOTE: only preserved for binary compatibility */
657 char *
658 ldif_put(
659 int type,
660 LDAP_CONST char *name,
661 LDAP_CONST char *val,
662 ber_len_t vlen )
664 return ldif_put_wrap( type, name, val, vlen, 0 );
667 char *
668 ldif_put_wrap(
669 int type,
670 LDAP_CONST char *name,
671 LDAP_CONST char *val,
672 ber_len_t vlen,
673 ber_len_t wrap )
675 char *buf, *p;
676 ber_len_t nlen;
678 nlen = ( name != NULL ) ? strlen( name ) : 0;
680 buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED_WRAP( nlen, vlen, wrap ) + 1 );
682 if ( buf == NULL ) {
683 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
684 _("ldif_type_and_value: malloc failed!"));
685 return NULL;
688 p = buf;
689 ldif_sput_wrap( &p, type, name, val, vlen, wrap );
690 *p = '\0';
692 return( buf );
695 int ldif_is_not_printable(
696 LDAP_CONST char *val,
697 ber_len_t vlen )
699 if( vlen == 0 || val == NULL ) {
700 return -1;
703 if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
704 isgraph( (unsigned char) val[vlen-1] ) )
706 ber_len_t i;
708 for ( i = 0; val[i]; i++ ) {
709 if ( !isascii( val[i] ) || !isprint( (unsigned char) val[i] ) ) {
710 return 1;
714 return 0;
717 return 1;
720 LDIFFP *
721 ldif_open(
722 LDAP_CONST char *file,
723 LDAP_CONST char *mode
726 FILE *fp = fopen( file, mode );
727 LDIFFP *lfp = NULL;
729 if ( fp ) {
730 lfp = ber_memalloc( sizeof( LDIFFP ));
731 if ( lfp == NULL ) {
732 fclose( fp );
733 return NULL;
735 lfp->fp = fp;
736 lfp->prev = NULL;
738 return lfp;
741 LDIFFP *
742 ldif_open_mem(
743 char *ldif,
744 size_t size,
745 LDAP_CONST char *mode
748 #ifdef HAVE_FMEMOPEN
749 FILE *fp = fmemopen( ldif, size, mode );
750 LDIFFP *lfp = NULL;
752 if ( fp ) {
753 lfp = ber_memalloc( sizeof( LDIFFP ));
754 lfp->fp = fp;
755 lfp->prev = NULL;
757 return lfp;
758 #else /* !HAVE_FMEMOPEN */
759 return NULL;
760 #endif /* !HAVE_FMEMOPEN */
763 void
764 ldif_close(
765 LDIFFP *lfp
768 LDIFFP *prev;
770 while ( lfp ) {
771 fclose( lfp->fp );
772 prev = lfp->prev;
773 ber_memfree( lfp );
774 lfp = prev;
778 #define LDIF_MAXLINE 4096
781 * ldif_read_record - read an ldif record. Return 1 for success, 0 for EOF,
782 * -1 for error.
785 ldif_read_record(
786 LDIFFP *lfp,
787 unsigned long *lno, /* ptr to line number counter */
788 char **bufp, /* ptr to malloced output buffer */
789 int *buflenp ) /* ptr to length of *bufp */
791 char line[LDIF_MAXLINE], *nbufp;
792 ber_len_t lcur = 0, len;
793 int last_ch = '\n', found_entry = 0, stop, top_comment = 0;
795 for ( stop = 0; !stop; last_ch = line[len-1] ) {
796 /* If we're at the end of this file, see if we should pop
797 * back to a previous file. (return from an include)
799 while ( feof( lfp->fp )) {
800 pop:
801 if ( lfp->prev ) {
802 LDIFFP *tmp = lfp->prev;
803 fclose( lfp->fp );
804 *lfp = *tmp;
805 ber_memfree( tmp );
806 } else {
807 stop = 1;
808 break;
811 if ( !stop ) {
812 if ( fgets( line, sizeof( line ), lfp->fp ) == NULL ) {
813 if ( !found_entry && !ferror( lfp->fp ) ) {
814 /* ITS#9811 Reached the end looking for an entry, try again */
815 goto pop;
817 stop = 1;
818 len = 0;
819 } else {
820 len = strlen( line );
824 if ( stop ) {
825 /* Add \n in case the file does not end with newline */
826 if (last_ch != '\n') {
827 len = 1;
828 line[0] = '\n';
829 line[1] = '\0';
830 goto last;
832 break;
835 /* Squash \r\n to \n */
836 if ( len > 1 && line[len-2] == '\r' ) {
837 len--;
838 line[len] = '\0';
839 line[len-1] = '\n';
842 if ( last_ch == '\n' ) {
843 (*lno)++;
845 if ( line[0] == '\n' ) {
846 if ( !found_entry ) {
847 lcur = 0;
848 top_comment = 0;
849 continue;
851 break;
854 if ( !found_entry ) {
855 if ( line[0] == '#' ) {
856 top_comment = 1;
857 } else if ( ! ( top_comment && line[0] == ' ' ) ) {
858 /* Found a new entry */
859 found_entry = 1;
861 if ( isdigit( (unsigned char) line[0] ) ) {
862 /* skip index */
863 continue;
865 if ( !strncasecmp( line, "include:",
866 STRLENOF("include:"))) {
867 FILE *fp2;
868 char *ptr;
869 found_entry = 0;
871 if ( line[len-1] == '\n' ) {
872 len--;
873 line[len] = '\0';
876 ptr = line + STRLENOF("include:");
877 while (isspace((unsigned char) *ptr)) ptr++;
878 fp2 = ldif_open_url( ptr );
879 if ( fp2 ) {
880 LDIFFP *lnew = ber_memalloc( sizeof( LDIFFP ));
881 if ( lnew == NULL ) {
882 fclose( fp2 );
883 return 0;
885 lnew->prev = lfp->prev;
886 lnew->fp = lfp->fp;
887 lfp->prev = lnew;
888 lfp->fp = fp2;
889 line[len] = '\n';
890 len++;
891 continue;
892 } else {
893 /* We failed to open the file, this should
894 * be reported as an error somehow.
896 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
897 _("ldif_read_record: include %s failed\n"), ptr );
898 return -1;
905 last:
906 if ( *buflenp - lcur <= len ) {
907 *buflenp += len + LDIF_MAXLINE;
908 nbufp = ber_memrealloc( *bufp, *buflenp );
909 if( nbufp == NULL ) {
910 return 0;
912 *bufp = nbufp;
914 strcpy( *bufp + lcur, line );
915 lcur += len;
918 return( found_entry );