/** * Assign the to-be-parsed string. */ rsRetVal rsParsAssignString(rsParsObj *pThis, cstr_t *pCStr) { rsCHECKVALIDOBJECT(pThis, OIDrsPars); rsCHECKVALIDOBJECT(pCStr, OIDrsCStr); pThis->pCStr = pCStr; pThis->iCurrPos = 0; return RS_RET_OK; }
/* Parse a quoted string ("-some-data") from the given position. * Leading whitespace before the first quote is skipped. During * parsing, escape sequences are detected and converted: * \\ - backslash character * \" - quote character * any other value \<somechar> is reserved for future use. * * After return, the parse pointer is paced after the trailing * quote. * * Output: * ppCStr Pointer to the parsed string - must be freed by caller and * does NOT include the quotes. * rgerhards, 2005-09-19 */ rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr) { register unsigned char *pC; cstr_t *pCStr; DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsPars); if((iRet = parsSkipAfterChar(pThis, '"')) != RS_RET_OK) FINALIZE; pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; /* OK, we most probably can obtain a value... */ CHKiRet(rsCStrConstruct(&pCStr)); while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) { if(*pC == '"') { break; /* we are done! */ } else if(*pC == '\\') { ++pThis->iCurrPos; ++pC; if(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) { /* in this case, we copy the escaped character * to the output buffer (but do not rely on this, * we might later introduce other things, like \007! */ if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) { rsCStrDestruct(&pCStr); FINALIZE; } } } else { /* regular character */ if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) { rsCStrDestruct (&pCStr); FINALIZE; } } ++pThis->iCurrPos; ++pC; } if(*pC == '"') { ++pThis->iCurrPos; /* 'eat' trailing quote */ } else { /* error - improperly quoted string! */ rsCStrDestruct (&pCStr); ABORT_FINALIZE(RS_RET_MISSING_TRAIL_QUOTE); } /* We got the string, let's finish it... */ if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) { rsCStrDestruct (&pCStr); FINALIZE; } /* done! */ *ppCStr = pCStr; finalize_it: RETiRet; }
/* Converts the CStr object to a classical zero-terminated C string, * returns that string and destroys the CStr object. The returned string * MUST be freed by the caller. The function might return NULL if * no memory can be allocated. * * This is the NEW replacement for rsCStrConvSzStrAndDestruct which does * no longer utilize a special buffer but soley works on pBuf (and also * assumes that cstrFinalize had been called). * * Parameters are as follows: * pointer to the object, pointer to string-pointer to receive string and * bRetNULL: 0 - must not return NULL on empty string, return "" in that * case, 1 - return NULL instead of an empty string. * PLEASE NOTE: the caller must free the memory returned in ppSz in any case * (except, of course, if it is NULL). */ rsRetVal cstrConvSzStrAndDestruct(cstr_t *pThis, uchar **ppSz, int bRetNULL) { DEFiRet; uchar* pRetBuf; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); assert(ppSz != NULL); assert(bRetNULL == 0 || bRetNULL == 1); if(pThis->pBuf == NULL) { if(bRetNULL == 0) { CHKmalloc(pRetBuf = MALLOC(sizeof(uchar))); *pRetBuf = '\0'; } else { pRetBuf = NULL; } } else pRetBuf = pThis->pBuf; *ppSz = pRetBuf; finalize_it: /* We got it, now free the object ourselfs. Please note * that we can NOT use the rsCStrDestruct function as it would * also free the sz String buffer, which we pass on to the user. */ RSFREEOBJ(pThis); RETiRet; }
/* compare a rsCStr object with a classical sz string. This function * is almost identical to rsCStrZsStrCmp(), but it also takes an offset * to the CStr object from where the comparison is to start. * I have thought quite a while if it really makes sense to more or * less duplicate the code. After all, if you call it with an offset of * zero, the functionality is exactly the same. So it looks natural to * just have a single function. However, supporting the offset requires * some (few) additional integer operations. While they are few, they * happen at places in the code that is run very frequently. All in all, * I have opted for performance and thus duplicated the code. I hope * this is a good, or at least acceptable, compromise. * rgerhards, 2005-09-26 * This function also has an offset-pointer which allows to * specify *where* the compare operation should begin in * the CStr. If everything is to be compared, it must be set * to 0. If some leading bytes are to be skipped, it must be set * to the first index that is to be compared. It must not be * set higher than the string length (this is considered a * program bug and will lead to unpredictable results and program aborts). * rgerhards 2005-09-26 */ int rsCStrOffsetSzStrCmp(cstr_t *pCS1, size_t iOffset, uchar *psz, size_t iLenSz) { BEGINfunc rsCHECKVALIDOBJECT(pCS1, OIDrsCStr); assert(iOffset < pCS1->iStrLen); assert(psz != NULL); assert(iLenSz == strlen((char*)psz)); /* just make sure during debugging! */ if((pCS1->iStrLen - iOffset) == iLenSz) { /* we are using iLenSz below, because the lengths * are equal and iLenSz is faster to access */ if(iLenSz == 0) { return 0; /* zero-sized strings are equal ;) */ ENDfunc } else { /* we now have two non-empty strings of equal * length, so we need to actually check if they * are equal. */ register size_t i; for(i = 0 ; i < iLenSz ; ++i) { if(pCS1->pBuf[i+iOffset] != psz[i]) return pCS1->pBuf[i+iOffset] - psz[i]; } /* if we arrive here, the strings are equal */ return 0; ENDfunc } }
/* peek at the character at the parse pointer * the caller must ensure that the parse pointer is not * at the end of the parse buffer (e.g. by first calling * parsIsAtEndOfParseString). * rgerhards, 2005-09-27 */ char parsPeekAtCharAtParsPtr(rsParsObj *pThis) { rsCHECKVALIDOBJECT(pThis, OIDrsPars); assert(pThis->iCurrPos < rsCStrLen(pThis->pCStr)); return(*(pThis->pCStr->pBuf + pThis->iCurrPos)); }
/* Converts the CStr object to a classical zero-terminated C string * and returns that string. The caller must not free it and must not * destroy the CStr object as long as the ascii string is used. * This function may return NULL, if the string is currently NULL. This * is a feature, not a bug. If you need non-NULL in any case, use * rsCStrGetSzStrNoNULL() instead. * rgerhards, 2005-09-15 */ uchar* rsCStrGetSzStr(cstr_t *pThis) { size_t i; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if(pThis->pBuf != NULL) if(pThis->pszBuf == NULL) { /* we do not yet have a usable sz version - so create it... */ if((pThis->pszBuf = MALLOC((pThis->iStrLen + 1) * sizeof(uchar))) == NULL) { /* TODO: think about what to do - so far, I have no bright * idea... rgerhards 2005-09-07 */ } else { /* we can create the sz String */ /* now copy it while doing a sanity check. The string might contain a * \0 byte. There is no way how a sz string can handle this. For * the time being, we simply replace it with space - something that * could definitely be improved (TODO). * 2005-09-15 rgerhards */ for(i = 0 ; i < pThis->iStrLen ; ++i) { if(pThis->pBuf[i] == '\0') pThis->pszBuf[i] = ' '; else pThis->pszBuf[i] = pThis->pBuf[i]; } /* write terminator... */ pThis->pszBuf[i] = '\0'; } } return(pThis->pszBuf); }
/* Sets the string object to the classigal sz-string provided. * Any previously stored vlaue is discarded. If a NULL pointer * the the new value (pszNew) is provided, an empty string is * created (this is NOT an error!). * rgerhards, 2005-10-18 */ rsRetVal rsCStrSetSzStr(cstr_t *pThis, uchar *pszNew) { rsCHECKVALIDOBJECT(pThis, OIDrsCStr); free(pThis->pBuf); free(pThis->pszBuf); if(pszNew == NULL) { pThis->iStrLen = 0; pThis->iBufSize = 0; pThis->pBuf = NULL; pThis->pszBuf = NULL; } else { pThis->iStrLen = strlen((char*)pszNew); pThis->iBufSize = pThis->iStrLen; pThis->pszBuf = NULL; /* now save the new value */ if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) { RSFREEOBJ(pThis); return RS_RET_OUT_OF_MEMORY; } /* we do NOT need to copy the \0! */ memcpy(pThis->pBuf, pszNew, pThis->iStrLen); } return RS_RET_OK; }
/* check if a sz-type string starts with a CStr object. This function * is initially written to support the "startswith" property-filter * comparison operation. Maybe it also has other needs. * This functions is modelled after the strcmp() series, thus a * return value of 0 indicates that the string starts with the * sequence while -1 indicates it does not! * rgerhards 2005-10-19 */ int rsCStrSzStrStartsWithCStr(cstr_t *pCS1, uchar *psz, size_t iLenSz) { register int i; int iMax; rsCHECKVALIDOBJECT(pCS1, OIDrsCStr); assert(psz != NULL); assert(iLenSz == strlen((char*)psz)); /* just make sure during debugging! */ if(iLenSz >= pCS1->iStrLen) { /* we need to checkusing pCS1->iStrLen charactes at maximum, thus * we move it to iMax. */ iMax = pCS1->iStrLen; if(iMax == 0) return 0; /* yes, it starts with a zero-sized string ;) */ else { /* we now have something to compare, so let's do it... */ for(i = 0 ; i < iMax ; ++i) { if(psz[i] != pCS1->pBuf[i]) return psz[i] - pCS1->pBuf[i]; } /* if we arrive here, the string actually starts with pCS1 */ return 0; } } else return -1; /* pCS1 is less then psz */ }
/* The same as rsCStrStartsWithSzStr(), but does a case-insensitive * comparison. TODO: consolidate the two. * rgerhards 2008-02-28 */ int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz) { register size_t i; rsCHECKVALIDOBJECT(pCS1, OIDrsCStr); assert(psz != NULL); assert(iLenSz == strlen((char*)psz)); /* just make sure during debugging! */ if(pCS1->iStrLen >= iLenSz) { /* we are using iLenSz below, because we need to check * iLenSz characters at maximum (start with!) */ if(iLenSz == 0) return 0; /* yes, it starts with a zero-sized string ;) */ else { /* we now have something to compare, so let's do it... */ for(i = 0 ; i < iLenSz ; ++i) { if(tolower(pCS1->pBuf[i]) != tolower(psz[i])) return tolower(pCS1->pBuf[i]) - tolower(psz[i]); } /* if we arrive here, the string actually starts with psz */ return 0; } } else return -1; /* pCS1 is less then psz */ }
/* Skip everything up to a specified character. * Returns with ParsePointer set BEHIND this character. * Returns RS_RET_OK if found, RS_RET_NOT_FOUND if not * found. In that case, the ParsePointer is moved to the * last character of the string. * 2005-09-19 rgerhards */ rsRetVal parsSkipAfterChar(rsParsObj *pThis, char c) { register unsigned char *pC; DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsPars); pC = rsCStrGetBufBeg(pThis->pCStr); while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) { if(pC[pThis->iCurrPos] == c) break; ++pThis->iCurrPos; } /* delimiter found? */ if(pC[pThis->iCurrPos] == c) { if(pThis->iCurrPos+1 < rsCStrLen(pThis->pCStr)) { iRet = RS_RET_OK; pThis->iCurrPos++; /* 'eat' delimiter */ } else { iRet = RS_RET_FOUND_AT_STRING_END; } } else { iRet = RS_RET_NOT_FOUND; } RETiRet; }
/* parse an integer. The parse pointer is advanced to the * position directly after the last digit. If no digit is * found at all, an error is returned and the parse pointer * is NOT advanced. * PORTABILITY WARNING: this function depends on the * continues representation of digits inside the character * set (as in ASCII). * rgerhards 2005-09-27 */ rsRetVal parsInt(rsParsObj *pThis, int* pInt) { unsigned char *pC; int iVal; rsCHECKVALIDOBJECT(pThis, OIDrsPars); assert(pInt != NULL); iVal = 0; pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; /* order of checks is important, else we might do * mis-addressing! (off by one) */ if(pThis->iCurrPos >= rsCStrLen(pThis->pCStr)) return RS_RET_NO_MORE_DATA; if(!isdigit((int)*pC)) return RS_RET_NO_DIGIT; while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && isdigit((int)*pC)) { iVal = iVal * 10 + *pC - '0'; ++pThis->iCurrPos; ++pC; } *pInt = iVal; return RS_RET_OK; }
/* Converts the CStr object to a classical sz string and returns that. * Same restrictions as in rsCStrGetSzStr() applies (see there!). This * function here guarantees that a valid string is returned, even if * the CStr object currently holds a NULL pointer string buffer. If so, * "" is returned. * rgerhards 2005-10-19 * WARNING: The returned pointer MUST NOT be freed, as it may be * obtained from that constant memory pool (in case of NULL!) */ uchar* rsCStrGetSzStrNoNULL(cstr_t *pThis) { rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if(pThis->pBuf == NULL) return (uchar*) ""; else return rsCStrGetSzStr(pThis); }
/* return the position of the parse pointer */ int rsParsGetParsePointer(rsParsObj *pThis) { rsCHECKVALIDOBJECT(pThis, OIDrsPars); if(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) return pThis->iCurrPos; else return rsCStrLen(pThis->pCStr) - 1; }
/** * Destruct a rsPars object and its associated string. * rgerhards, 2005-09-26 */ rsRetVal rsParsDestruct(rsParsObj *pThis) { rsCHECKVALIDOBJECT(pThis, OIDrsPars); if(pThis->pCStr != NULL) rsCStrDestruct(&pThis->pCStr); RSFREEOBJ(pThis); return RS_RET_OK; }
rsRetVal rsCStrAppendInt(cstr_t *pThis, long i) { DEFiRet; uchar szBuf[32]; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); CHKiRet(srUtilItoA((char*) szBuf, sizeof(szBuf), i)); iRet = rsCStrAppendStr(pThis, szBuf); finalize_it: RETiRet; }
/* compare two string objects - works like strcmp(), but operates * on CStr objects. Please note that this version here is * faster in the majority of cases, simply because it can * rely on StrLen. * rgerhards 2005-09-19 * fixed bug, in which only the last byte was actually compared * in equal-size strings. * rgerhards, 2005-09-26 */ int rsCStrCStrCmp(cstr_t *pCS1, cstr_t *pCS2) { rsCHECKVALIDOBJECT(pCS1, OIDrsCStr); rsCHECKVALIDOBJECT(pCS2, OIDrsCStr); if(pCS1->iStrLen == pCS2->iStrLen) if(pCS1->iStrLen == 0) return 0; /* zero-sized string are equal ;) */ else { /* we now have two non-empty strings of equal * length, so we need to actually check if they * are equal. */ register size_t i; for(i = 0 ; i < pCS1->iStrLen ; ++i) { if(pCS1->pBuf[i] != pCS2->pBuf[i]) return pCS1->pBuf[i] - pCS2->pBuf[i]; } /* if we arrive here, the strings are equal */ return 0; } else return pCS1->iStrLen - pCS2->iStrLen; }
/* Parse string up to a delimiter. * * Input: * cDelim - the delimiter * The following two are for whitespace stripping, * 0 means "no", 1 "yes" * - bTrimLeading * - bTrimTrailing * * Output: * ppCStr Pointer to the parsed string - must be freed by caller! */ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing) { DEFiRet; register unsigned char *pC; cstr_t *pCStr; rsCHECKVALIDOBJECT(pThis, OIDrsPars); CHKiRet(rsCStrConstruct(&pCStr)); if(bTrimLeading) parsSkipWhitespace(pThis); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) { if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) { rsCStrDestruct(&pCStr); FINALIZE; } ++pThis->iCurrPos; ++pC; } if(*pC == cDelim) { ++pThis->iCurrPos; /* eat delimiter */ } /* We got the string, now take it and see if we need to * remove anything at its end. */ if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) { rsCStrDestruct (&pCStr); FINALIZE; } if(bTrimTrailing) { if((iRet = rsCStrTrimTrailingWhiteSpace(pCStr)) != RS_RET_OK) { rsCStrDestruct (&pCStr); FINALIZE; } } /* done! */ *ppCStr = pCStr; finalize_it: RETiRet; }
/* Skip whitespace. Often used to trim parsable entries. * Returns with ParsePointer set to first non-whitespace * character (or at end of string). */ rsRetVal parsSkipWhitespace(rsParsObj *pThis) { register unsigned char *pC; rsCHECKVALIDOBJECT(pThis, OIDrsPars); pC = rsCStrGetBufBeg(pThis->pCStr); while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) { if(!isspace((int)*(pC+pThis->iCurrPos))) break; ++pThis->iCurrPos; } return RS_RET_OK; }
/* Trim trailing whitespace from a given string */ rsRetVal rsCStrTrimTrailingWhiteSpace(cstr_t *pThis) { register int i; register uchar *pC; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); i = pThis->iStrLen; pC = pThis->pBuf + i - 1; while(i > 0 && isspace((int)*pC)) { --pC; --i; } /* i now is the new string length! */ pThis->iStrLen = i; return RS_RET_OK; }
/* Parse string up to a delimiter. * * Input: * cDelim - the delimiter. Note that SP within a value always is a delimiter, * so cDelim is actually an *additional* delimiter. * The following two are for whitespace stripping, * 0 means "no", 1 "yes" * - bTrimLeading * - bTrimTrailing * - bConvLower - convert string to lower case? * * Output: * ppCStr Pointer to the parsed string - must be freed by caller! */ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing, int bConvLower) { DEFiRet; register unsigned char *pC; cstr_t *pCStr = NULL; rsCHECKVALIDOBJECT(pThis, OIDrsPars); CHKiRet(rsCStrConstruct(&pCStr)); if(bTrimLeading) parsSkipWhitespace(pThis); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) { CHKiRet(cstrAppendChar(pCStr, bConvLower ? tolower(*pC) : *pC)); ++pThis->iCurrPos; ++pC; } if(pThis->iCurrPos < cstrLen(pThis->pCStr)) { //BUGFIX!! ++pThis->iCurrPos; /* eat delimiter */ } /* We got the string, now take it and see if we need to * remove anything at its end. */ CHKiRet(cstrFinalize(pCStr)); if(bTrimTrailing) { CHKiRet(cstrTrimTrailingWhiteSpace(pCStr)); } /* done! */ *ppCStr = pCStr; finalize_it: if(iRet != RS_RET_OK) { if(pCStr != NULL) rsCStrDestruct(&pCStr); } RETiRet; }
/* append a string of known length. In this case, we make sure we do at most * one additional memory allocation. * I optimized this function to use memcpy(), among others. Consider it a * rewrite (which may be good to know in case of bugs) -- rgerhards, 2008-01-07 */ rsRetVal rsCStrAppendStrWithLen(cstr_t *pThis, uchar* psz, size_t iStrLen) { DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); assert(psz != NULL); /* does the string fit? */ if(pThis->iStrLen + iStrLen > pThis->iBufSize) { CHKiRet(rsCStrExtendBuf(pThis, iStrLen)); /* need more memory! */ } /* ok, now we always have sufficient continues memory to do a memcpy() */ memcpy(pThis->pBuf + pThis->iStrLen, psz, iStrLen); pThis->iStrLen += iStrLen; finalize_it: RETiRet; }
/* Trim trailing whitespace from a given string */ rsRetVal cstrTrimTrailingWhiteSpace(cstr_t *pThis) { register int i; register uchar *pC; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if(pThis->iStrLen == 0) goto done; /* empty string -> nothing to trim ;) */ i = pThis->iStrLen; pC = pThis->pBuf + i - 1; while(i > 0 && isspace((int)*pC)) { --pC; --i; } /* i now is the new string length! */ pThis->iStrLen = i; pThis->pBuf[pThis->iStrLen] = '0'; /* we always have this space */ done: return RS_RET_OK; }
/* Truncate characters from the end of the string. * rgerhards 2005-09-15 */ rsRetVal rsCStrTruncate(cstr_t *pThis, size_t nTrunc) { rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if(pThis->iStrLen < nTrunc) return RS_TRUNCAT_TOO_LARGE; pThis->iStrLen -= nTrunc; if(pThis->pszBuf != NULL) { /* in this case, we adjust the psz representation * by writing a new \0 terminator - this is by far * the fastest way and outweights the additional memory * required. 2005-9-19 rgerhards. */ pThis->pszBuf[pThis->iStrLen] = '\0'; } return RS_RET_OK; }
/* Skip whitespace. Often used to trim parsable entries. * Returns with ParsePointer set to first non-whitespace * character (or at end of string). * If bRequireOne is set to true, at least one whitespace * must exist, else an error is returned. */ rsRetVal parsSkipWhitespace(rsParsObj *pThis) { register unsigned char *pC; int numSkipped; DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsPars); pC = rsCStrGetBufBeg(pThis->pCStr); numSkipped = 0; while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) { if(!isspace((int)*(pC+pThis->iCurrPos))) break; ++pThis->iCurrPos; ++numSkipped; } RETiRet; }
/* construct from CStr object. only the counted string is * copied, not the szString. * rgerhards 2005-10-18 */ rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom) { DEFiRet; cstr_t *pThis; assert(ppThis != NULL); rsCHECKVALIDOBJECT(pFrom, OIDrsCStr); CHKiRet(rsCStrConstruct(&pThis)); pThis->iBufSize = pThis->iStrLen = pFrom->iStrLen; if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) { RSFREEOBJ(pThis); ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } /* copy properties */ memcpy(pThis->pBuf, pFrom->pBuf, pThis->iStrLen); *ppThis = pThis; finalize_it: RETiRet; }
rsRetVal parsAddrWithBits(rsParsObj *pThis, struct NetAddr **pIP, int *pBits) { register uchar *pC; uchar *pszIP; uchar *pszTmp; struct addrinfo hints, *res = NULL; cstr_t *pCStr; DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsPars); assert(pIP != NULL); assert(pBits != NULL); CHKiRet(cstrConstruct(&pCStr)); parsSkipWhitespace(pThis); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; /* we parse everything until either '/', ',' or * whitespace. Validity will be checked down below. */ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != '/' && *pC != ',' && !isspace((int)*pC)) { if((iRet = cstrAppendChar(pCStr, *pC)) != RS_RET_OK) { cstrDestruct (&pCStr); FINALIZE; } ++pThis->iCurrPos; ++pC; } /* We got the string, let's finish it... */ if((iRet = cstrFinalize(pCStr)) != RS_RET_OK) { cstrDestruct(&pCStr); FINALIZE; } /* now we have the string and must check/convert it to * an NetAddr structure. */ CHKiRet(cstrConvSzStrAndDestruct(pCStr, &pszIP, 0)); *pIP = calloc(1, sizeof(struct NetAddr)); if (*((char*)pszIP) == '[') { pszTmp = (uchar*)strchr ((char*)pszIP, ']'); if (pszTmp == NULL) { free (pszIP); ABORT_FINALIZE(RS_RET_INVALID_IP); } *pszTmp = '\0'; memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_INET6; # ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; # else hints.ai_flags = AI_NUMERICHOST; # endif switch(getaddrinfo ((char*)pszIP+1, NULL, &hints, &res)) { case 0: (*pIP)->addr.NetAddr = MALLOC (res->ai_addrlen); memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo (res); break; case EAI_NONAME: F_SET((*pIP)->flags, ADDR_NAME|ADDR_PRI6); (*pIP)->addr.HostWildcard = strdup ((const char*)pszIP+1); break; default: free (pszIP); free (*pIP); ABORT_FINALIZE(RS_RET_ERR); } if(*pC == '/') { /* mask bits follow, let's parse them! */ ++pThis->iCurrPos; /* eat slash */ if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) { free (pszIP); free (*pIP); FINALIZE; } /* we need to refresh pointer (changed by parsInt()) */ pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; } else { /* no slash, so we assume a single host (/128) */ *pBits = 128; } } else { /* now parse IPv4 */ memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_INET; # ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; # else hints.ai_flags = AI_NUMERICHOST; # endif switch(getaddrinfo ((char*)pszIP, NULL, &hints, &res)) { case 0: (*pIP)->addr.NetAddr = MALLOC (res->ai_addrlen); memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo (res); break; case EAI_NONAME: F_SET((*pIP)->flags, ADDR_NAME); (*pIP)->addr.HostWildcard = strdup ((const char*)pszIP); break; default: free (pszIP); free (*pIP); ABORT_FINALIZE(RS_RET_ERR); } if(*pC == '/') { /* mask bits follow, let's parse them! */ ++pThis->iCurrPos; /* eat slash */ if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) { free (pszIP); free (*pIP); FINALIZE; } /* we need to refresh pointer (changed by parsInt()) */ pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; } else { /* no slash, so we assume a single host (/32) */ *pBits = 32; } } free(pszIP); /* no longer needed */ /* skip to next processable character */ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && (*pC == ',' || isspace((int)*pC))) { ++pThis->iCurrPos; ++pC; } iRet = RS_RET_OK; finalize_it: RETiRet; }
/* tell if the parsepointer is at the end of the * to-be-parsed string. Returns 1, if so, 0 * otherwise. rgerhards, 2005-09-27 */ int parsIsAtEndOfParseString(rsParsObj *pThis) { rsCHECKVALIDOBJECT(pThis, OIDrsPars); return (pThis->iCurrPos < rsCStrLen(pThis->pCStr)) ? 0 : 1; }
int cstrLen(cstr_t *pThis) { rsCHECKVALIDOBJECT(pThis, OIDrsCStr); return(pThis->iStrLen); }