| /* |
| * Copyright (c) 1989, 1990, 1991 by the University of Washington |
| * |
| * For copying and distribution information, please see the file |
| * <copyright.h>. |
| * |
| * v1.2.2 - 11/19/91 (mmt) - added MSDOS & OS2 stuff |
| * v1.2.1 - 09/23/91 (gf) - made it use regex.h---much nicer |
| * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas |
| * v1.1.1 - 08/30/91 (bpk) - added VMS support; cast index() |
| */ |
| |
| /* |
| * Miscellaneous routines pulled from ~beta/lib/pfs and ~beta/lib/filters |
| */ |
| |
| #include <copyright.h> |
| #include <stdio.h> |
| |
| #include <errno.h> |
| |
| #ifdef VMS |
| # ifdef WOLLONGONG |
| # include "twg$tcp:[netdist.include]netdb.h" |
| # else /* not Wollongong */ |
| # ifdef UCX |
| # include netdb |
| # else /* Multinet */ |
| # include "multinet_root:[multinet.include]netdb.h" |
| # endif |
| # endif |
| # include <vms.h> |
| #else /* not VMS */ |
| # include <sys/types.h> |
| # include <pmachine.h> |
| # ifdef NEED_STRING_H |
| # include <string.h> |
| # else |
| # include <strings.h> |
| # endif |
| # ifndef CUTCP |
| # include <netdb.h> |
| # endif |
| # if !defined(MSDOS) || defined(OS2) |
| # include <sys/file.h> |
| # include <sys/param.h> |
| # endif |
| #endif /* VMS */ |
| |
| #include <pfs.h> |
| #include <pprot.h> |
| #include <perrno.h> |
| #include <pcompat.h> |
| #include <pauthent.h> |
| |
| #include "regex.h" |
| |
| int pfs_enable = PMAP_ATSIGN; |
| |
| #ifndef FALSE |
| # define TRUE 1 |
| # define FALSE 0 |
| #endif |
| |
| extern int vl_comp(VLINK vl1,VLINK vl2); |
| extern int vl_equal(VLINK vl1,VLINK vl2); |
| |
| /* |
| * wcmatch - Match string s against template containing widlcards |
| * |
| * WCMATCH takes a string and a template, and returns |
| * true if the string matches the template, and |
| * FALSE otherwise. |
| * |
| * ARGS: s - string to be tested |
| * template - Template containing optional wildcards |
| * |
| * RETURNS: TRUE (non-zero) on match. FALSE (0) otherwise. |
| * |
| * NOTE: If template is NULL, will return TRUE. |
| * |
| */ |
| |
| int wcmatch(char *s,char *template) |
| { |
| char temp[200]; |
| char *p = temp; |
| |
| if(!template) return(TRUE); |
| *p++ = '^'; |
| |
| while(*template) { |
| if(*template == '*') {*(p++)='.'; *(p++) = *(template++);} |
| else if(*template == '?') {*(p++)='.';template++;} |
| else if(*template == '.') {*(p++)='\\';*(p++)='.';template++;} |
| else if(*template == '[') {*(p++)='\\';*(p++)='[';template++;} |
| else if(*template == '$') {*(p++)='\\';*(p++)='$';template++;} |
| else if(*template == '^') {*(p++)='\\';*(p++)='^';template++;} |
| else if(*template == '\\') {*(p++)='\\';*(p++)='\\';template++;} |
| else *(p++) = *(template++); |
| } |
| |
| *p++ = '$'; |
| *p++ = '\0'; |
| |
| if(re_comp(temp)) return(FALSE); |
| |
| #ifdef AUX |
| if (re_exec(s) == (char *)NULL) |
| return 0; |
| return 1; |
| #else |
| return(re_exec(s)); |
| #endif |
| } |
| |
| /* |
| * ul_insert - Insert a union link at the right location |
| * |
| * UL_INSERT takes a directory and a union link to be added |
| * to a the list of union links in the directory. It then |
| * inserts the union link in the right spot in the linked |
| * list of union links associated with that directory. |
| * |
| * If an identical link already exists, then the link which |
| * would be evaluated earlier (closer to the front of the list) |
| * wins and the other one is freed. If this happens, an error |
| * will also be returned. |
| * |
| * ARGS: ul - link to be inserted |
| * vd - directory to get link |
| * p - vl that this link will apper after |
| * NULL - This vl will go at end of list |
| * vd - This vl will go at head of list |
| * |
| * RETURNS: Success, or UL_INSERT_ALREADY_THERE or UL_INSERT_SUPERSEDING |
| */ |
| |
| int ul_insert(VLINK ul,VDIR1 vd,VLINK p) |
| { |
| VLINK current; |
| |
| /* This is the first ul in the directory */ |
| if(vd->ulinks == NULL) { |
| vd->ulinks = ul; |
| ul->previous = NULL; |
| ul->next = NULL; |
| return(PSUCCESS); |
| } |
| |
| /* This ul will go at the head of the list */ |
| if(p == (VLINK) vd) { |
| ul->next = vd->ulinks; |
| ul->next->previous = ul; |
| vd->ulinks = ul; |
| ul->previous = NULL; |
| } |
| /* Otherwise, decide if it must be inserted at all */ |
| /* If an identical link appears before the position */ |
| /* at which the new one is to be inserted, we can */ |
| /* return without inserting it */ |
| else { |
| current = vd->ulinks; |
| |
| while(current) { |
| /* p == NULL means we insert after last link */ |
| if(!p && (current->next == NULL)) |
| p = current; |
| |
| if(vl_comp(current,ul) == 0) { |
| vlfree(ul); |
| return(UL_INSERT_ALREADY_THERE); |
| } |
| |
| if(current == p) break; |
| current = current->next; |
| } |
| |
| /* If current is null, p was not found */ |
| if(current == NULL) |
| return(UL_INSERT_POS_NOTFOUND); |
| |
| /* Insert ul */ |
| ul->next = p->next; |
| p->next = ul; |
| ul->previous = p; |
| if(ul->next) ul->next->previous = ul; |
| } |
| |
| /* Check for identical links after ul */ |
| current = ul->next; |
| |
| while(current) { |
| if(vl_comp(current,ul) == 0) { |
| current->previous->next = current->next; |
| if(current->next) |
| current->next->previous = current->previous; |
| vlfree(current); |
| return(UL_INSERT_SUPERSEDING); |
| } |
| current = current->next; |
| } |
| |
| return(PSUCCESS); |
| } |
| |
| /* |
| * vl_insert - Insert a directory link at the right location |
| * |
| * VL_INSERT takes a directory and a link to be added to a |
| * directory and inserts it in the linked list of links for |
| * that directory. |
| * |
| * If a link already exists with the same name, and if the |
| * information associated with the new link matches that in |
| * the existing link, an error is returned. If the information |
| * associated with the new link is different, but the magic numbers |
| * match, then the new link will be added as a replica of the |
| * existing link. If the magic numbers do not match, the new |
| * link will only be added to the list of "replicas" if the |
| * allow_conflict flag has been set. |
| * |
| * If the link is not added, an error is returned and the link |
| * is freed. Ordering for the list of links is by the link name. |
| * |
| * If vl is a union link, then VL_INSERT calls ul_insert with an |
| * added argument indicating the link is to be included at the |
| * end of the union link list. |
| * |
| * ARGS: vl - Link to be inserted, vd - directory to get link |
| * allow_conflict - insert links with conflicting names |
| * |
| * RETURNS: Success, or VL_INSERT_ALREADY_THERE |
| */ |
| |
| int vl_insert(VLINK vl,VDIR1 vd,int allow_conflict) |
| { |
| VLINK current; /* To step through list */ |
| VLINK crep; /* To step through list of replicas */ |
| int retval; /* Temp for checking returned values */ |
| |
| /* This can also be used to insert union links at end of list */ |
| if(vl->linktype == 'U') return(ul_insert(vl,vd,NULL)); |
| |
| /* If this is the first link in the directory */ |
| if(vd->links == NULL) { |
| vd->links = vl; |
| vl->previous = NULL; |
| vl->next = NULL; |
| vd->lastlink = vl; |
| return(PSUCCESS); |
| } |
| |
| /* If no sorting is to be done, just insert at end of list */ |
| if(allow_conflict == VLI_NOSORT) { |
| vd->lastlink->next = vl; |
| vl->previous = vd->lastlink; |
| vl->next = NULL; |
| vd->lastlink = vl; |
| return(PSUCCESS); |
| } |
| |
| /* If it is to be inserted at start of list */ |
| if(vl_comp(vl,vd->links) < 0) { |
| vl->next = vd->links; |
| vl->previous = NULL; |
| vl->next->previous = vl; |
| vd->links = vl; |
| return(PSUCCESS); |
| } |
| |
| current = vd->links; |
| |
| /* Otherwise, we must find the right spot to insert it */ |
| while((retval = vl_comp(vl,current)) > 0) { |
| if(!current->next) { |
| /* insert at end */ |
| vl->previous = current; |
| vl->next = NULL; |
| current->next = vl; |
| vd->lastlink = vl; |
| return(PSUCCESS); |
| } |
| current = current->next; |
| } |
| |
| /* If we found an equivilant entry already in list */ |
| if(!retval) { |
| if(vl_equal(vl,current)) { |
| vlfree(vl); |
| return(VL_INSERT_ALREADY_THERE); |
| } |
| if((allow_conflict == VLI_NOCONFLICT) && |
| ((vl->f_magic_no != current->f_magic_no) || |
| (vl->f_magic_no==0))) |
| return(VL_INSERT_CONFLICT); |
| /* Insert the link into the list of "replicas" */ |
| /* If magic is 0, then create a pseudo magic number */ |
| if(vl->f_magic_no == 0) vl->f_magic_no = -1; |
| crep = current->replicas; |
| if(!crep) { |
| current->replicas = vl; |
| vl->next = NULL; |
| vl->previous = NULL; |
| } |
| else { |
| while(crep->next) { |
| /* If magic was 0, then we need a unique magic number */ |
| if((crep->f_magic_no < 0) && (vl->f_magic_no < 1)) |
| (vl->f_magic_no)--; |
| crep = crep->next; |
| } |
| /* If magic was 0, then we need a unique magic number */ |
| if((crep->f_magic_no < 0) && (vl->f_magic_no < 1)) |
| (vl->f_magic_no)--; |
| crep->next = vl; |
| vl->previous = crep; |
| vl->next = NULL; |
| } |
| return(PSUCCESS); |
| } |
| |
| /* We found the spot where vl is to be inserted */ |
| vl->next = current; |
| vl->previous = current->previous; |
| current->previous = vl; |
| vl->previous->next = vl; |
| return(PSUCCESS); |
| } |
| |
| /* |
| * nlsindex - Find first instance of string 2 in string 1 following newline |
| * |
| * NLSINDEX scans string 1 for the first instance of string |
| * 2 that immediately follows a newline. If found, NLSINDEX |
| * returns a pointer to the first character of that instance. |
| * If no instance is found, NLSINDEX returns NULL (0). |
| * |
| * NOTE: This function is only useful for searching strings that |
| * consist of multiple lines. s1 is assumed to be preceeded |
| * by a newline. Thus, if s2 is at the start of s1, it will |
| * be found. |
| * ARGS: s1 - string to be searched |
| * s2 - string to be found |
| * RETURNS: First instance of s2 in s1, or NULL (0) if not found |
| */ |
| |
| char *nlsindex(char *s1,char *s2) |
| { |
| register int s2len = strlen(s2); |
| char *curline = s1; /* Pointer to start of current line */ |
| |
| /* In case s2 appears at start of s1 */ |
| if(strncmp(curline,s2,s2len) == 0) |
| return(curline); |
| |
| /* Check remaining lines of s1 */ |
| while((curline = strchr(curline,(int) '\n')) != NULL) { |
| curline++; |
| if(strncmp(curline,s2,s2len) == 0) |
| return(curline); |
| } |
| |
| /* We didn't find it */ |
| return(NULL); |
| } |
| |
| /* |
| * month_sname - Return a month name from it's number |
| * |
| * MONTH_SNAME takes a number in the range 0 |
| * to 12 and returns a pointer to a string |
| * representing the three letter abbreviation |
| * for that month. If the argument is out of |
| * range, MONTH_SNAME returns a pointer to "Unk". |
| * |
| * ARGS: n - Number of the month |
| * RETURNS: Abbreviation for selected month |
| */ |
| |
| char *month_sname(int n) |
| { |
| static char *name[] = { "Unk", |
| "Jan","Feb","Mar","Apr","May","Jun", |
| "Jul","Aug","Sep","Oct","Nov","Dec" |
| }; |
| return((n < 1 || n > 12) ? name[0] : name[n]); |
| } |
| |
| /* |
| * sindex - Find first instance of string 2 in string 1 |
| * |
| * SINDEX scans string 1 for the first instance of string |
| * 2. If found, SINDEX returns a pointer to the first |
| * character of that instance. If no instance is found, |
| * SINDEX returns NULL (0). |
| * |
| * ARGS: s1 - string to be searched |
| * s2 - string to be found |
| * RETURNS: First instance of s2 in s1, or NULL (0) if not found |
| */ |
| |
| char *sindex(char *s1,char *s2) |
| { |
| register int s2len = strlen(s2); |
| char *s = s1; /* Temp pointer to string */ |
| |
| /* Check for first character of s2 */ |
| while((s = strchr(s,(int) *s2)) != NULL) { |
| if(strncmp(s,s2,s2len) == 0) |
| return(s); |
| s++; |
| } |
| |
| /* We didn't find it */ |
| return(NULL); |
| } |
| |
| int scan_error(char *erst) |
| { |
| *p_err_string = '\0'; |
| |
| if(strncmp(erst,"NOT-A-DIRECTORY",15) == 0) |
| return(DIRSRV_NOT_DIRECTORY); |
| |
| if(strncmp(erst,"UNIMPLEMENTED",13) == 0) { |
| perrno = DIRSRV_UNIMPLEMENTED; |
| sscanf(erst+13,"%*[^\n \t\r]%*[ \t]%[^\n]",p_err_string); |
| return(perrno); |
| } |
| |
| if(strncmp(erst,"WARNING ",8) == 0) { |
| erst += 8; |
| *p_warn_string = '\0'; |
| sscanf(erst,"%*[^\n \t\r]%*[ \t]%[^\n]",p_warn_string); |
| /* Return values for warnings are negative */ |
| if(strncmp(erst,"OUT-OF-DATE",11) == 0) { |
| pwarn = PWARN_OUT_OF_DATE; |
| return(PSUCCESS); |
| } |
| if(strncmp(erst,"MESSAGE",7) == 0) { |
| pwarn = PWARN_MSG_FROM_SERVER; |
| return(PSUCCESS); |
| } |
| pwarn = PWARNING; |
| sscanf(erst,"%[^\n]",p_warn_string); |
| return(PSUCCESS); |
| } |
| else if(strncmp(erst,"ERROR",5) == 0) { |
| if(*(erst+5)) sscanf(erst+6,"%[^\n]",p_err_string); |
| perrno = DIRSRV_ERROR; |
| return(perrno); |
| } |
| /* The rest start with "FAILURE" */ |
| else if(strncmp(erst,"FAILURE",7) != 0) { |
| /* Unrecognized - Give warning, but return PSUCCESS */ |
| if(pwarn == 0) { |
| *p_warn_string = '\0'; |
| pwarn = PWARN_UNRECOGNIZED_RESP; |
| sscanf(erst,"%[^\n]",p_warn_string); |
| } |
| return(PSUCCESS); |
| } |
| |
| if(strncmp(erst,"FAILURE ",8) != 0) { |
| perrno = PFAILURE; |
| return(perrno); |
| } |
| erst += 8; |
| |
| sscanf(erst,"%*[^\n \t\r]%*[ \t]%[^\n]",p_err_string); |
| |
| /* Still to add */ |
| /* DIRSRV_AUTHENT_REQ 242 */ |
| /* DIRSRV_BAD_VERS 245 */ |
| |
| if(strncmp(erst,"NOT-FOUND",9) == 0) |
| perrno = DIRSRV_NOT_FOUND; |
| else if(strncmp(erst,"NOT-AUTHORIZED",13) == 0) |
| perrno = DIRSRV_NOT_AUTHORIZED; |
| else if(strncmp(erst,"ALREADY-EXISTS",14) == 0) |
| perrno = DIRSRV_ALREADY_EXISTS; |
| else if(strncmp(erst,"NAME-CONFLICT",13) == 0) |
| perrno = DIRSRV_NAME_CONFLICT; |
| else if(strncmp(erst,"SERVER-FAILED",13) == 0) |
| perrno = DIRSRV_SERVER_FAILED; |
| /* Use it whether it starts with FAILURE or not */ |
| else if(strncmp(erst,"NOT-A-DIRECTORY",15) == 0) |
| perrno = DIRSRV_NOT_DIRECTORY; |
| else perrno = PFAILURE; |
| |
| return(perrno); |
| } |
| |
| PATTRIB parse_attribute(char *line) |
| { |
| char l_precedence[MAX_DIR_LINESIZE]; |
| char l_name[MAX_DIR_LINESIZE]; |
| char l_type[MAX_DIR_LINESIZE]; |
| char l_value[MAX_DIR_LINESIZE]; |
| PATTRIB at; |
| int tmp; |
| |
| tmp = sscanf(line,"OBJECT-INFO %s %s %[^\n]", l_name, l_type, l_value); |
| |
| if(tmp < 3) { |
| tmp = sscanf(line,"LINK-INFO %s %s %s %[^\n]", l_precedence, |
| l_name, l_type, l_value); |
| if(tmp < 4) { |
| perrno = DIRSRV_BAD_FORMAT; |
| return(NULL); |
| } |
| } |
| |
| at = atalloc(); |
| |
| if(tmp == 4) { |
| if(strcmp(l_precedence,"CACHED") == 0) |
| at->precedence = ATR_PREC_CACHED; |
| else if(strcmp(l_precedence,"LINK") == 0) |
| at->precedence = ATR_PREC_LINK; |
| else if(strcmp(l_precedence,"REPLACEMENT") == 0) |
| at->precedence = ATR_PREC_REPLACE; |
| else if(strcmp(l_precedence,"ADDITIONAL") == 0) |
| at->precedence = ATR_PREC_ADD; |
| } |
| |
| at->aname = stcopy(l_name); |
| at->avtype = stcopy(l_type); |
| if(strcmp(l_type,"ASCII") == 0) |
| at->value.ascii = stcopy(l_value); |
| else if(strcmp(l_type,"LINK") == 0) { |
| char ftype[MAX_DIR_LINESIZE]; |
| char lname[MAX_DIR_LINESIZE]; |
| char htype[MAX_DIR_LINESIZE]; |
| char host[MAX_DIR_LINESIZE]; |
| char ntype[MAX_DIR_LINESIZE]; |
| char fname[MAX_DIR_LINESIZE]; |
| VLINK al; |
| |
| al = vlalloc(); |
| at->value.link = al; |
| |
| tmp = sscanf(l_value,"%c %s %s %s %s %s %s %d %d", |
| &(al->linktype), |
| ftype,lname,htype,host,ntype,fname, |
| &(al->version), |
| &(al->f_magic_no)); |
| if(tmp == 9) { |
| al->type = stcopyr(ftype,al->type); |
| al->name = stcopyr(unquote(lname),al->name); |
| al->hosttype = stcopyr(htype,al->hosttype); |
| al->host = stcopyr(host,al->host); |
| al->nametype = stcopyr(ntype,al->nametype); |
| al->filename = stcopyr(fname,al->filename); |
| } |
| else { |
| perrno = DIRSRV_BAD_FORMAT; |
| return(NULL); |
| } |
| |
| } |
| |
| return(at); |
| } |
| |
| /* |
| * nxtline - Find the next line in the string |
| * |
| * NXTLINE takes a string and returns a pointer to |
| * the character immediately following the next newline. |
| * |
| * ARGS: s - string to be searched |
| * |
| * RETURNS: Next line or NULL (0) on failure |
| */ |
| |
| char *nxtline(char *s) |
| /* String to be searched */ |
| { |
| s = strchr(s,(int) '\n'); |
| if(s) return(++s); |
| else return(NULL); |
| } |
| |
| |
| /* |
| * unquote - unquote string if necessary |
| * |
| * UNQUOTE takes a string and unquotes it if it has been quoted. |
| * |
| * ARGS: s - string to be unquoted |
| * |
| * RETURNS: The original string. If the string has been quoted, then the |
| * result appears in static storage, and must be copied if |
| * it is to last beyond the next call to quote. |
| * |
| */ |
| |
| char *unquote(char *s) |
| /* String to be quoted */ |
| { |
| static char unquoted[200]; |
| char *c = unquoted; |
| |
| if(*s != '\'') return(s); |
| |
| s++; |
| |
| /* This should really treat a quote followed by other */ |
| /* than a quote or a null as an error */ |
| while(*s) { |
| if(*s == '\'') s++; |
| if(*s) *c++ = *s++; |
| } |
| |
| *c++ = '\0'; |
| |
| return(unquoted); |
| } |
| |
| #if defined(DEBUG) && defined(STRSPN) |
| /* needed for -D option parsing */ |
| /* |
| * strspn - Count initial characters from chrs in s |
| * |
| * STRSPN counts the occurances of chacters from chrs |
| * in the string s preceeding the first occurance of |
| * a character not in s. |
| * |
| * ARGS: s - string to be checked |
| * chrs - string of characters we are looking for |
| * |
| * RETURNS: Count of initial characters from chrs in s |
| */ |
| |
| int strspn(char *s,char *chrs) |
| { |
| char *cp; /* Pointer to the current character in chrs */ |
| int count; /* Count of characters seen so far */ |
| |
| count = 0; |
| |
| while(*s) { |
| for(cp = chrs;*cp;cp++) |
| if(*cp == *s) { |
| s++; |
| count++; |
| goto done; |
| } |
| return(count); |
| done: |
| ; |
| } |
| return(count); |
| } |
| #endif |
| |
| #ifdef CUTCP |
| |
| char *inet_ntoa(struct in_addr in) |
| { |
| static char buff[36]; |
| |
| unsigned char *c = (char *) &in.address; |
| sprintf(buff,"%d.%d.%d.%d",*c,*(c+1),*(c+2),*(c+3)); |
| return(buff); |
| } |
| |
| long inet_addr(char *cp) |
| { |
| long value = 0; |
| unsigned v1,v2,v3,v4; |
| |
| v1 = v2 = v3 = v4 = 0xff; |
| sscanf(cp,"%d.%d.%d.%d",&v1,&v2,&v3,&v4); |
| value = (v1 << 24) | (v2 << 16) | (v3 << 8) | v4; |
| return(value); |
| } |
| |
| struct hostent *gethostbyname(char *name) |
| { |
| struct machinfo *mp; |
| int mnum; |
| unsigned long now; |
| static struct hostent ht; |
| extern int pfs_debug; |
| |
| mp = Shostlook(name); |
| if(!mp || (!mp->hostip[0])) { /* DNS lookup */ |
| #ifdef DEBUG |
| if (pfs_debug) |
| fprintf(stderr, "Domain name lookup of %s\n", name); |
| #endif |
| mnum = Sdomain(name); /* start a DNS lookup */ |
| now = time(NULL) + NS_TIMEOUT; |
| while(now > time(NULL)) { |
| int i, class, dat; |
| |
| Stask(); |
| i = Sgetevent(USERCLASS, &class, &dat); |
| if(i == DOMOK) { /* domain lookup ok */ |
| mp = Slooknum(mnum); |
| #ifdef DEBUG |
| if (pfs_debug) |
| fprintf(stderr, "Domain name lookup of %s Completed OK\n", name); |
| #endif |
| break; |
| } |
| } |
| if(!mp) { /* get here if timeout */ |
| #ifdef DEBUG |
| if (pfs_debug) |
| fprintf(stderr, "Domain name lookup of %s Failed\n", name); |
| #endif |
| return(NULL); |
| } |
| } |
| ht.h_addr = *((unsigned long *) mp->hostip); |
| ht.h_length = 4; |
| ht.h_addrtype = AF_INET; |
| return(&ht); |
| |
| } |
| #endif /* CUTCP */ |
| |
| #ifdef GETENV |
| /* |
| * Copyright (c) 1987 Regents of the University of California. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms are permitted |
| * provided that: (1) source distributions retain this entire copyright |
| * notice and comment, and (2) distributions including binaries display |
| * the following acknowledgement: ``This product includes software |
| * developed by the University of California, Berkeley and its contributors'' |
| * in the documentation or other materials provided with the distribution |
| * and in all advertising materials mentioning features or use of this |
| * software. Neither the name of the University nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| */ |
| |
| #if defined(LIBC_SCCS) && !defined(lint) |
| static char sccsid[] = "@(#)getenv.c 5.7 (Berkeley) 6/1/90"; |
| #endif /* LIBC_SCCS and not lint */ |
| |
| #include <stdlib.h> |
| #include <stddef.h> |
| |
| /* |
| * getenv -- |
| * Returns ptr to value associated with name, if any, else NULL. |
| */ |
| |
| char *getenv(char *name) |
| { |
| int offset; |
| char *_findenv(); |
| |
| return(_findenv(name, &offset)); |
| } |
| |
| /* |
| * _findenv -- |
| * Returns pointer to value associated with name, if any, else NULL. |
| * Sets offset to be the offset of the name/value combination in the |
| * environmental array, for use by setenv(3) and unsetenv(3). |
| * Explicitly removes '=' in argument name. |
| * |
| * This routine *should* be a static; don't use it. |
| */ |
| |
| char * _findenv(register char *name,int *offset) |
| { |
| extern char **environ; |
| register int len; |
| register char **P, *C; |
| |
| for (C = name, len = 0; *C && *C != '='; ++C, ++len); |
| for (P = environ; *P; ++P) |
| if (!strncmp(*P, name, len)) |
| if (*(C = *P + len) == '=') { |
| *offset = P - environ; |
| return(++C); |
| } |
| return(NULL); |
| } |
| #endif |