Avoid yydebug compiler warning
[heimdal.git] / lib / roken / getcap.c
bloba341c104b1b1f95b34589e5655da925774ddea37
1 /* $NetBSD: getcap.c,v 1.29 1999/03/29 09:27:29 abs Exp $ */
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Casey Leedom of Lawrence Livermore National Laboratory.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <config.h>
37 #include "roken.h"
39 #include <sys/types.h>
40 #include <ctype.h>
41 #if defined(HAVE_DB_185_H)
42 #include <db_185.h>
43 #elif defined(HAVE_DB_H)
44 #include <db.h>
45 #endif
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <limits.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
54 #define BFRAG 1024
55 #define ESC ('[' & 037) /* ASCII ESC */
56 #define MAX_RECURSION 32 /* maximum getent recursion */
57 #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
59 #define RECOK (char)0
60 #define TCERR (char)1
61 #define SHADOW (char)2
63 static size_t topreclen; /* toprec length */
64 static char *toprec; /* Additional record specified by cgetset() */
65 static int gottoprec; /* Flag indicating retrieval of toprecord */
67 #ifdef USE_DB
68 static int cdbget (DB *, char **, const char *);
69 #endif
70 static int getent (char **, size_t *, char **, int, const char *, int, char *);
71 static int nfcmp (char *, char *);
74 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetset(const char *ent);
75 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL cgetcap(char *buf, const char *cap, int type);
76 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetent(char **buf, char **db_array, const char *name);
77 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetmatch(const char *buf, const char *name);
78 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetclose(void);
79 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetstr(char *buf, const char *cap, char **str);
80 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetustr(char *buf, const char *cap, char **str);
81 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetnum(char *buf, const char *cap, long *num);
83 * Cgetset() allows the addition of a user specified buffer to be added
84 * to the database array, in effect "pushing" the buffer on top of the
85 * virtual database. 0 is returned on success, -1 on failure.
87 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
88 cgetset(const char *ent)
90 const char *source, *check;
91 char *dest;
93 if (ent == NULL) {
94 if (toprec)
95 free(toprec);
96 toprec = NULL;
97 topreclen = 0;
98 return (0);
100 topreclen = strlen(ent);
101 if ((toprec = malloc (topreclen + 1)) == NULL) {
102 errno = ENOMEM;
103 return (-1);
105 gottoprec = 0;
107 source=ent;
108 dest=toprec;
109 while (*source) { /* Strip whitespace */
110 *dest++ = *source++; /* Do not check first field */
111 while (*source == ':') {
112 check=source+1;
113 while (*check && (isspace((unsigned char)*check) ||
114 (*check=='\\' && isspace((unsigned char)check[1]))))
115 ++check;
116 if( *check == ':' )
117 source=check;
118 else
119 break;
123 *dest=0;
125 return (0);
129 * Cgetcap searches the capability record buf for the capability cap with
130 * type `type'. A pointer to the value of cap is returned on success, NULL
131 * if the requested capability couldn't be found.
133 * Specifying a type of ':' means that nothing should follow cap (:cap:).
134 * In this case a pointer to the terminating ':' or NUL will be returned if
135 * cap is found.
137 * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
138 * return NULL.
140 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
141 cgetcap(char *buf, const char *cap, int type)
143 char *bp;
144 const char *cp;
146 bp = buf;
147 for (;;) {
149 * Skip past the current capability field - it's either the
150 * name field if this is the first time through the loop, or
151 * the remainder of a field whose name failed to match cap.
153 for (;;)
154 if (*bp == '\0')
155 return (NULL);
156 else
157 if (*bp++ == ':')
158 break;
161 * Try to match (cap, type) in buf.
163 for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
164 continue;
165 if (*cp != '\0')
166 continue;
167 if (*bp == '@')
168 return (NULL);
169 if (type == ':') {
170 if (*bp != '\0' && *bp != ':')
171 continue;
172 return(bp);
174 if (*bp != type)
175 continue;
176 bp++;
177 return (*bp == '@' ? NULL : bp);
179 /* NOTREACHED */
183 * Cgetent extracts the capability record name from the NULL terminated file
184 * array db_array and returns a pointer to a malloc'd copy of it in buf.
185 * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
186 * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success,
187 * -1 if the requested record couldn't be found, -2 if a system error was
188 * encountered (couldn't open/read a file, etc.), and -3 if a potential
189 * reference loop is detected.
191 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
192 cgetent(char **buf, char **db_array, const char *name)
194 size_t dummy;
196 return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
200 * Getent implements the functions of cgetent. If fd is non-negative,
201 * *db_array has already been opened and fd is the open file descriptor. We
202 * do this to save time and avoid using up file descriptors for tc=
203 * recursions.
205 * Getent returns the same success/failure codes as cgetent. On success, a
206 * pointer to a malloc'ed capability record with all tc= capabilities fully
207 * expanded and its length (not including trailing ASCII NUL) are left in
208 * *cap and *len.
210 * Basic algorithm:
211 * + Allocate memory incrementally as needed in chunks of size BFRAG
212 * for capability buffer.
213 * + Recurse for each tc=name and interpolate result. Stop when all
214 * names interpolated, a name can't be found, or depth exceeds
215 * MAX_RECURSION.
217 static int
218 getent(char **cap, size_t *len, char **db_array, int fd,
219 const char *name, int depth, char *nfield)
221 char *r_end, *rp = NULL, **db_p; /* pacify gcc */
222 int myfd = 0, eof, foundit;
223 char *record;
224 int tc_not_resolved;
227 * Return with ``loop detected'' error if we've recursed more than
228 * MAX_RECURSION times.
230 if (depth > MAX_RECURSION)
231 return (-3);
234 * Check if we have a top record from cgetset().
236 if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
237 size_t tmplen = topreclen + BFRAG;
238 if ((record = malloc (tmplen)) == NULL) {
239 errno = ENOMEM;
240 return (-2);
242 (void)strlcpy(record, toprec, tmplen);
243 db_p = db_array;
244 rp = record + topreclen + 1;
245 r_end = rp + BFRAG;
246 goto tc_exp;
249 * Allocate first chunk of memory.
251 if ((record = malloc(BFRAG)) == NULL) {
252 errno = ENOMEM;
253 return (-2);
255 r_end = record + BFRAG;
256 foundit = 0;
258 * Loop through database array until finding the record.
261 for (db_p = db_array; *db_p != NULL; db_p++) {
262 eof = 0;
265 * Open database if not already open.
268 if (fd >= 0) {
269 (void)lseek(fd, (off_t)0, SEEK_SET);
270 } else {
271 #ifdef USE_DB
272 char pbuf[_POSIX_PATH_MAX];
273 char *cbuf;
274 size_t clen;
275 int retval;
276 DB *capdbp;
278 (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
279 if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
280 != NULL) {
281 free(record);
282 retval = cdbget(capdbp, &record, name);
283 if (retval < 0) {
284 /* no record available */
285 (void)capdbp->close(capdbp);
286 return (retval);
288 /* save the data; close frees it */
289 clen = strlen(record);
290 cbuf = malloc(clen + 1);
291 if (cbuf == NULL)
292 return (-2);
293 memmove(cbuf, record, clen + 1);
294 if (capdbp->close(capdbp) < 0) {
295 free(cbuf);
296 return (-2);
298 *len = clen;
299 *cap = cbuf;
300 return (retval);
301 } else
302 #endif
304 fd = open(*db_p, O_RDONLY, 0);
305 if (fd < 0) {
306 /* No error on unfound file. */
307 continue;
309 myfd = 1;
313 * Find the requested capability record ...
316 char buf[BUFSIZ];
317 char *b_end, *bp, *cp;
318 int c, slash;
321 * Loop invariants:
322 * There is always room for one more character in record.
323 * R_end always points just past end of record.
324 * Rp always points just past last character in record.
325 * B_end always points just past last character in buf.
326 * Bp always points at next character in buf.
327 * Cp remembers where the last colon was.
329 b_end = buf;
330 bp = buf;
331 cp = 0;
332 slash = 0;
333 for (;;) {
336 * Read in a line implementing (\, newline)
337 * line continuation.
339 rp = record;
340 for (;;) {
341 if (bp >= b_end) {
342 int n;
344 n = read(fd, buf, sizeof(buf));
345 if (n <= 0) {
346 if (myfd)
347 (void)close(fd);
348 if (n < 0) {
349 free(record);
350 return (-2);
351 } else {
352 fd = -1;
353 eof = 1;
354 break;
357 b_end = buf+n;
358 bp = buf;
361 c = *bp++;
362 if (c == '\n') {
363 if (slash) {
364 slash = 0;
365 rp--;
366 continue;
367 } else
368 break;
370 if (slash) {
371 slash = 0;
372 cp = 0;
374 if (c == ':') {
376 * If the field was `empty' (i.e.
377 * contained only white space), back up
378 * to the colon (eliminating the
379 * field).
381 if (cp)
382 rp = cp;
383 else
384 cp = rp;
385 } else if (c == '\\') {
386 slash = 1;
387 } else if (c != ' ' && c != '\t') {
389 * Forget where the colon was, as this
390 * is not an empty field.
392 cp = 0;
394 *rp++ = c;
397 * Enforce loop invariant: if no room
398 * left in record buffer, try to get
399 * some more.
401 if (rp >= r_end) {
402 u_int pos;
403 size_t newsize;
405 pos = rp - record;
406 newsize = r_end - record + BFRAG;
407 record = realloc(record, newsize);
408 if (record == NULL) {
409 errno = ENOMEM;
410 if (myfd)
411 (void)close(fd);
412 return (-2);
414 r_end = record + newsize;
415 rp = record + pos;
418 /* Eliminate any white space after the last colon. */
419 if (cp)
420 rp = cp + 1;
421 /* Loop invariant lets us do this. */
422 *rp++ = '\0';
425 * If encountered eof check next file.
427 if (eof)
428 break;
431 * Toss blank lines and comments.
433 if (*record == '\0' || *record == '#')
434 continue;
437 * See if this is the record we want ...
439 if (cgetmatch(record, name) == 0) {
440 if (nfield == NULL || !nfcmp(nfield, record)) {
441 foundit = 1;
442 break; /* found it! */
447 if (foundit)
448 break;
451 if (!foundit)
452 return (-1);
455 * Got the capability record, but now we have to expand all tc=name
456 * references in it ...
458 tc_exp: {
459 char *newicap, *s;
460 size_t ilen, newilen;
461 int diff, iret, tclen;
462 char *icap, *scan, *tc, *tcstart, *tcend;
465 * Loop invariants:
466 * There is room for one more character in record.
467 * R_end points just past end of record.
468 * Rp points just past last character in record.
469 * Scan points at remainder of record that needs to be
470 * scanned for tc=name constructs.
472 scan = record;
473 tc_not_resolved = 0;
474 for (;;) {
475 if ((tc = cgetcap(scan, "tc", '=')) == NULL)
476 break;
479 * Find end of tc=name and stomp on the trailing `:'
480 * (if present) so we can use it to call ourselves.
482 s = tc;
483 for (;;)
484 if (*s == '\0')
485 break;
486 else
487 if (*s++ == ':') {
488 *(s - 1) = '\0';
489 break;
491 tcstart = tc - 3;
492 tclen = s - tcstart;
493 tcend = s;
495 iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
496 NULL);
497 newicap = icap; /* Put into a register. */
498 newilen = ilen;
499 if (iret != 0) {
500 /* an error */
501 if (iret < -1) {
502 if (myfd)
503 (void)close(fd);
504 free(record);
505 return (iret);
507 if (iret == 1)
508 tc_not_resolved = 1;
509 /* couldn't resolve tc */
510 if (iret == -1) {
511 *(s - 1) = ':';
512 scan = s - 1;
513 tc_not_resolved = 1;
514 continue;
518 /* not interested in name field of tc'ed record */
519 s = newicap;
520 for (;;)
521 if (*s == '\0')
522 break;
523 else
524 if (*s++ == ':')
525 break;
526 newilen -= s - newicap;
527 newicap = s;
529 /* make sure interpolated record is `:'-terminated */
530 s += newilen;
531 if (*(s-1) != ':') {
532 *s = ':'; /* overwrite NUL with : */
533 newilen++;
537 * Make sure there's enough room to insert the
538 * new record.
540 diff = newilen - tclen;
541 if (diff >= r_end - rp) {
542 u_int pos, tcpos, tcposend;
543 size_t newsize;
545 pos = rp - record;
546 newsize = r_end - record + diff + BFRAG;
547 tcpos = tcstart - record;
548 tcposend = tcend - record;
549 record = realloc(record, newsize);
550 if (record == NULL) {
551 errno = ENOMEM;
552 if (myfd)
553 (void)close(fd);
554 free(icap);
555 return (-2);
557 r_end = record + newsize;
558 rp = record + pos;
559 tcstart = record + tcpos;
560 tcend = record + tcposend;
564 * Insert tc'ed record into our record.
566 s = tcstart + newilen;
567 memmove(s, tcend, (size_t)(rp - tcend));
568 memmove(tcstart, newicap, newilen);
569 rp += diff;
570 free(icap);
573 * Start scan on `:' so next cgetcap works properly
574 * (cgetcap always skips first field).
576 scan = s-1;
581 * Close file (if we opened it), give back any extra memory, and
582 * return capability, length and success.
584 if (myfd)
585 (void)close(fd);
586 *len = rp - record - 1; /* don't count NUL */
587 if (r_end > rp)
588 if ((record =
589 realloc(record, (size_t)(rp - record))) == NULL) {
590 errno = ENOMEM;
591 return (-2);
594 *cap = record;
595 if (tc_not_resolved)
596 return (1);
597 return (0);
600 #ifdef USE_DB
601 static int
602 cdbget(DB *capdbp, char **bp, const char *name)
604 DBT key;
605 DBT data;
607 /* LINTED key is not modified */
608 key.data = (char *)name;
609 key.size = strlen(name);
611 for (;;) {
612 /* Get the reference. */
613 switch(capdbp->get(capdbp, &key, &data, 0)) {
614 case -1:
615 return (-2);
616 case 1:
617 return (-1);
620 /* If not an index to another record, leave. */
621 if (((char *)data.data)[0] != SHADOW)
622 break;
624 key.data = (char *)data.data + 1;
625 key.size = data.size - 1;
628 *bp = (char *)data.data + 1;
629 return (((char *)(data.data))[0] == TCERR ? 1 : 0);
631 #endif /* USE_DB */
634 * Cgetmatch will return 0 if name is one of the names of the capability
635 * record buf, -1 if not.
638 cgetmatch(const char *buf, const char *name)
640 const char *np, *bp;
643 * Start search at beginning of record.
645 bp = buf;
646 for (;;) {
648 * Try to match a record name.
650 np = name;
651 for (;;)
652 if (*np == '\0') {
653 if (*bp == '|' || *bp == ':' || *bp == '\0')
654 return (0);
655 else
656 break;
657 } else
658 if (*bp++ != *np++)
659 break;
662 * Match failed, skip to next name in record.
664 bp--; /* a '|' or ':' may have stopped the match */
665 for (;;)
666 if (*bp == '\0' || *bp == ':')
667 return (-1); /* match failed totally */
668 else
669 if (*bp++ == '|')
670 break; /* found next name */
674 static FILE *pfp;
675 static int slash;
676 static char **dbp;
678 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
679 cgetclose(void)
681 if (pfp != NULL) {
682 (void)fclose(pfp);
683 pfp = NULL;
685 dbp = NULL;
686 gottoprec = 0;
687 slash = 0;
688 return(0);
692 * Cgetstr retrieves the value of the string capability cap from the
693 * capability record pointed to by buf. A pointer to a decoded, NUL
694 * terminated, malloc'd copy of the string is returned in the char *
695 * pointed to by str. The length of the string not including the trailing
696 * NUL is returned on success, -1 if the requested string capability
697 * couldn't be found, -2 if a system error was encountered (storage
698 * allocation failure).
700 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
701 cgetstr(char *buf, const char *cap, char **str)
703 u_int m_room;
704 const char *bp;
705 char *mp;
706 int len;
707 char *mem, *nmem;
709 *str = NULL;
712 * Find string capability cap
714 bp = cgetcap(buf, cap, '=');
715 if (bp == NULL)
716 return (-1);
719 * Conversion / storage allocation loop ... Allocate memory in
720 * chunks SFRAG in size.
722 if ((mem = malloc(SFRAG)) == NULL) {
723 errno = ENOMEM;
724 return (-2); /* couldn't even allocate the first fragment */
726 m_room = SFRAG;
727 mp = mem;
729 while (*bp != ':' && *bp != '\0') {
731 * Loop invariants:
732 * There is always room for one more character in mem.
733 * Mp always points just past last character in mem.
734 * Bp always points at next character in buf.
736 if (*bp == '^') {
737 bp++;
738 if (*bp == ':' || *bp == '\0')
739 break; /* drop unfinished escape */
740 *mp++ = *bp++ & 037;
741 } else if (*bp == '\\') {
742 bp++;
743 if (*bp == ':' || *bp == '\0')
744 break; /* drop unfinished escape */
745 if ('0' <= *bp && *bp <= '7') {
746 int n, i;
748 n = 0;
749 i = 3; /* maximum of three octal digits */
750 do {
751 n = n * 8 + (*bp++ - '0');
752 } while (--i && '0' <= *bp && *bp <= '7');
753 *mp++ = n;
755 else switch (*bp++) {
756 case 'b': case 'B':
757 *mp++ = '\b';
758 break;
759 case 't': case 'T':
760 *mp++ = '\t';
761 break;
762 case 'n': case 'N':
763 *mp++ = '\n';
764 break;
765 case 'f': case 'F':
766 *mp++ = '\f';
767 break;
768 case 'r': case 'R':
769 *mp++ = '\r';
770 break;
771 case 'e': case 'E':
772 *mp++ = ESC;
773 break;
774 case 'c': case 'C':
775 *mp++ = ':';
776 break;
777 default:
779 * Catches '\', '^', and
780 * everything else.
782 *mp++ = *(bp-1);
783 break;
785 } else
786 *mp++ = *bp++;
787 m_room--;
790 * Enforce loop invariant: if no room left in current
791 * buffer, try to get some more.
793 if (m_room == 0) {
794 size_t size = mp - mem;
796 if ((nmem = realloc(mem, size + SFRAG)) == NULL) {
797 free(mem);
798 return (-2);
800 mem = nmem;
801 m_room = SFRAG;
802 mp = mem + size;
805 *mp++ = '\0'; /* loop invariant let's us do this */
806 m_room--;
807 len = mp - mem - 1;
810 * Give back any extra memory and return value and success.
812 if (m_room != 0) {
813 if ((nmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
814 free(mem);
815 return (-2);
817 mem = nmem;
819 *str = mem;
820 return (len);
824 * Cgetustr retrieves the value of the string capability cap from the
825 * capability record pointed to by buf. The difference between cgetustr()
826 * and cgetstr() is that cgetustr does not decode escapes but rather treats
827 * all characters literally. A pointer to a NUL terminated malloc'd
828 * copy of the string is returned in the char pointed to by str. The
829 * length of the string not including the trailing NUL is returned on success,
830 * -1 if the requested string capability couldn't be found, -2 if a system
831 * error was encountered (storage allocation failure).
833 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
834 cgetustr(char *buf, const char *cap, char **str)
836 u_int m_room;
837 const char *bp;
838 char *mp;
839 int len;
840 char *mem;
843 * Find string capability cap
845 if ((bp = cgetcap(buf, cap, '=')) == NULL)
846 return (-1);
849 * Conversion / storage allocation loop ... Allocate memory in
850 * chunks SFRAG in size.
852 if ((mem = malloc(SFRAG)) == NULL) {
853 errno = ENOMEM;
854 return (-2); /* couldn't even allocate the first fragment */
856 m_room = SFRAG;
857 mp = mem;
859 while (*bp != ':' && *bp != '\0') {
861 * Loop invariants:
862 * There is always room for one more character in mem.
863 * Mp always points just past last character in mem.
864 * Bp always points at next character in buf.
866 *mp++ = *bp++;
867 m_room--;
870 * Enforce loop invariant: if no room left in current
871 * buffer, try to get some more.
873 if (m_room == 0) {
874 size_t size = mp - mem;
876 if ((mem = realloc(mem, size + SFRAG)) == NULL)
877 return (-2);
878 m_room = SFRAG;
879 mp = mem + size;
882 *mp++ = '\0'; /* loop invariant let's us do this */
883 m_room--;
884 len = mp - mem - 1;
887 * Give back any extra memory and return value and success.
889 if (m_room != 0)
890 if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
891 return (-2);
892 *str = mem;
893 return (len);
897 * Cgetnum retrieves the value of the numeric capability cap from the
898 * capability record pointed to by buf. The numeric value is returned in
899 * the long pointed to by num. 0 is returned on success, -1 if the requested
900 * numeric capability couldn't be found.
902 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
903 cgetnum(char *buf, const char *cap, long *num)
905 long n;
906 int base, digit;
907 const char *bp;
910 * Find numeric capability cap
912 bp = cgetcap(buf, cap, '#');
913 if (bp == NULL)
914 return (-1);
917 * Look at value and determine numeric base:
918 * 0x... or 0X... hexadecimal,
919 * else 0... octal,
920 * else decimal.
922 if (*bp == '0') {
923 bp++;
924 if (*bp == 'x' || *bp == 'X') {
925 bp++;
926 base = 16;
927 } else
928 base = 8;
929 } else
930 base = 10;
933 * Conversion loop ...
935 n = 0;
936 for (;;) {
937 if ('0' <= *bp && *bp <= '9')
938 digit = *bp - '0';
939 else if ('a' <= *bp && *bp <= 'f')
940 digit = 10 + *bp - 'a';
941 else if ('A' <= *bp && *bp <= 'F')
942 digit = 10 + *bp - 'A';
943 else
944 break;
946 if (digit >= base)
947 break;
949 n = n * base + digit;
950 bp++;
954 * Return value and success.
956 *num = n;
957 return (0);
962 * Compare name field of record.
964 static int
965 nfcmp(char *nf, char *rec)
967 char *cp, tmp;
968 int ret;
970 for (cp = rec; *cp != ':'; cp++)
973 tmp = *(cp + 1);
974 *(cp + 1) = '\0';
975 ret = strcmp(nf, rec);
976 *(cp + 1) = tmp;
978 return (ret);