#endif
int BaseStrBufSize = 64;
+const char *StrBufNOTNULL = ((char*) NULL) - 1;
+
/**
* Private Structure for the Stringbuffer
*/
NewSize *= 2;
NewBuf= (char*) malloc(NewSize);
+ if (NewBuf == NULL)
+ return -1;
+
if (KeepOriginal && (Buf->BufUsed > 0))
{
memcpy(NewBuf, Buf->buf, Buf->BufUsed);
*FreeMe = NULL;
}
+/**
+ * \brief flatten a Buffer to the Char * we return
+ * Its a double pointer, so it can NULL your pointer
+ * so fancy SIG11 appear instead of random results
+ * The Calle then owns the buffer and is responsible for freeing it.
+ * \param SmashMe Pointer Pointer to the buffer to release Buf from and free
+ * \return the pointer of the buffer; Callee owns the memory thereafter.
+ */
+char *SmashStrBuf (StrBuf **SmashMe)
+{
+ char *Ret;
+
+ if (*SmashMe == NULL)
+ return NULL;
+#ifdef SIZE_DEBUG
+ if (hFreeDbglog == -1){
+ pid_t pid = getpid();
+ char path [SIZ];
+ snprintf(path, SIZ, "/tmp/libcitadel_strbuf_realloc.log.%d", pid);
+ hFreeDbglog = open(path, O_APPEND|O_CREAT|O_WRONLY);
+ }
+ if ((*SmashMe)->nIncreases > 0)
+ {
+ char buf[SIZ * 3];
+ long n;
+ n = snprintf(buf, SIZ * 3, "S+|%ld|%ld|%ld|%s|%s|\n",
+ (*SmashMe)->nIncreases,
+ (*SmashMe)->BufUsed,
+ (*SmashMe)->BufSize,
+ (*SmashMe)->bt,
+ (*SmashMe)->bt_lastinc);
+ n = write(hFreeDbglog, buf, n);
+ }
+ else
+ {
+ char buf[128];
+ long n;
+ n = snprintf(buf, 128, "S_|0|%ld%ld|\n",
+ (*SmashMe)->BufUsed,
+ (*SmashMe)->BufSize);
+ n = write(hFreeDbglog, buf, n);
+ }
+#endif
+ Ret = (*SmashMe)->buf;
+ free(*SmashMe);
+ *SmashMe = NULL;
+ return Ret;
+}
+
/**
* \brief Release the buffer
* If you want put your StrBuf into a Hash, use this as Destructor.
Buf->buf[Buf->BufUsed] = '\0';
}
+/**
+ * \brief Callback for cURL to append the webserver reply to a buffer
+ * params pre-defined by the cURL API; see man 3 curl for mre info
+ */
+size_t CurlFillStrBuf_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+
+ StrBuf *Target;
+
+ Target = stream;
+ if (ptr == NULL)
+ return 0;
+
+ StrBufAppendBufPlain(Target, ptr, size * nmemb, 0);
+ return size * nmemb;
+}
+
/**
* \brief Escape a string for feeding out as a URL while appending it to a Buffer
* \param Source source buffer; set to NULL if you just have a C-String
* \param PlainIn Plain-C string to append; set to NULL if unused
*/
-void StrMsgEscAppend(StrBuf *Target, StrBuf *Source, const char *PlainIn)
+void StrMsgEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
{
const char *aptr, *eiptr;
char *tptr, *eptr;
*tptr = '\0';
}
+
+
+/*
+ * \brief Append a string, escaping characters which have meaning in ICAL.
+ * [\n,]
+ * \param Target target buffer
+ * \param Source source buffer; set to NULL if you just have a C-String
+ * \param PlainIn Plain-C string to append; set to NULL if unused
+ */
+void StrIcalEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
+{
+ const char *aptr, *eiptr;
+ char *tptr, *eptr;
+ long len;
+
+ if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
+ return ;
+
+ if (PlainIn != NULL) {
+ aptr = PlainIn;
+ len = strlen(PlainIn);
+ eiptr = aptr + len;
+ }
+ else {
+ aptr = Source->buf;
+ eiptr = aptr + Source->BufUsed;
+ len = Source->BufUsed;
+ }
+
+ if (len == 0)
+ return;
+
+ eptr = Target->buf + Target->BufSize - 8;
+ tptr = Target->buf + Target->BufUsed;
+
+ while (aptr < eiptr){
+ if(tptr + 3 >= eptr) {
+ IncreaseBuf(Target, 1, -1);
+ eptr = Target->buf + Target->BufSize - 8;
+ tptr = Target->buf + Target->BufUsed;
+ }
+
+ if (*aptr == '\n') {
+ *tptr = '\\';
+ Target->BufUsed++;
+ tptr++;
+ *tptr = 'n';
+ Target->BufUsed++;
+ }
+ else if (*aptr == '\r') {
+ *tptr = '\\';
+ Target->BufUsed++;
+ tptr++;
+ *tptr = 'r';
+ Target->BufUsed++;
+ }
+ else if (*aptr == ',') {
+ *tptr = '\\';
+ Target->BufUsed++;
+ tptr++;
+ *tptr = ',';
+ Target->BufUsed++;
+ } else {
+ *tptr = *aptr;
+ Target->BufUsed++;
+ }
+ tptr++; aptr++;
+ }
+ *tptr = '\0';
+}
+
/*
* \brief Append a string, escaping characters which have meaning in JavaScript strings .
*
eptr = Target->buf + Target->BufSize - 3;
bptr = Target->buf + Target->BufUsed;
}
- else if (*aptr == '"') {
+ if (*aptr == '"') {
*bptr = '\\';
bptr ++;
*bptr = '"';
/* Hack and slash */
if (*s) {
- memmove(d, s, Source->BufUsed - (s - Source->buf) + 1);
- Source->BufUsed -= (ReducedBy + 1);
+ memmove(d, s, Source->BufUsed - (s - Source->buf));
+ Source->BufUsed += ReducedBy;
}
else if (d == Source->buf) {
*d = 0;
}
else {
*--d = 0;
- Source->BufUsed -= (ReducedBy + 1);
+ Source->BufUsed += ReducedBy;
}
/*
while (*s) {
}
if (len >= dest->BufSize) {
dest->BufUsed = len;
- if (!IncreaseBuf(dest, 1, -1))
+ if (IncreaseBuf(dest, 1, -1) < 0) {
+ dest->BufUsed --;
break;
+ }
}
if ( (current_token == parmnum) &&
(*s != separator)) {
+/**
+ * \briefa string tokenizer; Bounds checker
+ * function to make shure whether StrBufExtract_NextToken and friends have reached the end of the string.
+ * \param Source our tokenbuffer
+ * \param pStart the token iterator pointer to inspect
+ * \returns whether the revolving pointer is inside of the search range
+ */
+int StrBufHaveNextToken(const StrBuf *Source, const char **pStart)
+{
+ if ((Source == NULL) ||
+ (*pStart == StrBufNOTNULL) ||
+ (Source->BufUsed == 0))
+ {
+ return 0;
+ }
+ if (*pStart == NULL)
+ {
+ return 1;
+ }
+ else if (*pStart > Source->buf + Source->BufUsed)
+ {
+ return 0;
+ }
+ else if (*pStart <= Source->buf)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
/**
* \brief a string tokenizer
* \param dest Destination StringBuffer
* \param Source StringBuffer to read into
- * \param pStart pointer to the end of the last token. Feed with NULL.
+ * \param pStart pointer to the end of the last token. Feed with NULL on start.
* \param separator tokenizer param
* \returns -1 if not found, else length of token.
*/
int StrBufExtract_NextToken(StrBuf *dest, const StrBuf *Source, const char **pStart, char separator)
{
- const char *s, *EndBuffer; //* source * /
- int len = 0; //* running total length of extracted string * /
- int current_token = 0; //* token currently being processed * /
+ const char *s; /* source */
+ const char *EndBuffer; /* end stop of source buffer */
+ int current_token = 0; /* token currently being processed */
+ int len = 0; /* running total length of extracted string */
+
+ if ((Source == NULL) ||
+ (Source->BufUsed == 0) )
+ {
+ *pStart = StrBufNOTNULL;
+ return -1;
+ }
- if (dest != NULL) {
+ EndBuffer = Source->buf + Source->BufUsed;
+
+ if (dest != NULL)
+ {
dest->buf[0] = '\0';
dest->BufUsed = 0;
}
else
- return(-1);
-
- if ((Source == NULL) ||
- (Source->BufUsed ==0)) {
- return(-1);
+ {
+ *pStart = EndBuffer + 1;
+ return -1;
}
- if (*pStart == NULL)
- *pStart = Source->buf;
-
- EndBuffer = Source->buf + Source->BufUsed;
- if ((*pStart < Source->buf) ||
- (*pStart > EndBuffer)) {
- return (-1);
+ if (*pStart == NULL)
+ {
+ *pStart = Source->buf; /* we're starting to examine this buffer. */
+ }
+ else if ((*pStart < Source->buf) ||
+ (*pStart > EndBuffer ) )
+ {
+ return -1; /* no more tokens to find. */
}
-
s = *pStart;
-
- //cit_backtrace();
- //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
-
- while ((s<EndBuffer) && !IsEmptyStr(s)) {
- if (*s == separator) {
+ /* start to find the next token */
+ while ((s <= EndBuffer) &&
+ (current_token == 0) )
+ {
+ if (*s == separator)
+ {
+ /* we found the next token */
++current_token;
}
- if (len >= dest->BufSize) {
+
+ if (len >= dest->BufSize)
+ {
+ /* our Dest-buffer isn't big enough, increase it. */
dest->BufUsed = len;
- if (!IncreaseBuf(dest, 1, -1)) {
- *pStart = EndBuffer + 1;
+
+ if (IncreaseBuf(dest, 1, -1) < 0) {
+ /* WHUT? no more mem? bail out. */
+ s = EndBuffer;
+ dest->BufUsed --;
break;
}
}
- if ( (current_token == 0) &&
- (*s != separator)) {
- dest->buf[len] = *s;
- ++len;
- }
- else if (current_token > 0) {
- *pStart = s;
- break;
+
+ if ( (current_token == 0 ) && /* are we in our target token? */
+ (!IsEmptyStr(s) ) &&
+ (separator != *s) ) /* don't copy the token itself */
+ {
+ dest->buf[len] = *s; /* Copy the payload */
+ ++len; /* remember the bigger size. */
}
+
++s;
}
- *pStart = s;
- (*pStart) ++;
+ /* did we reach the end? */
+ if ((s > EndBuffer)) {
+ EndBuffer = StrBufNOTNULL;
+ *pStart = EndBuffer;
+ }
+ else {
+ *pStart = s; /* remember the position for the next run */
+ }
+
+ /* sanitize our extracted token */
dest->buf[len] = '\0';
- dest->BufUsed = len;
- //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
- //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
- return(len);
+ dest->BufUsed = len;
+
+ return (len);
}
}
+static const char *ErrRBLF_WrongFDFlags="StrBufTCP_read_buffered_line_fast: don't work with fdflags & O_NONBLOCK";
+static const char *ErrRBLF_SelectFailed="StrBufTCP_read_buffered_line_fast: Select failed without reason";
+static const char *ErrRBLF_NotEnoughSentFromServer="StrBufTCP_read_buffered_line_fast: No complete line was sent from peer";
/**
* \brief Read a line from socket
* flushes and closes the FD on error
}
fdflags = fcntl(*fd, F_GETFL);
- if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
+ if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
+ *Error = ErrRBLF_WrongFDFlags;
return -1;
+ }
pch = NULL;
while ((nSuccessLess < timeout) && (pch == NULL)) {
*Error = strerror(errno);
close (*fd);
*fd = -1;
+ if (*Error == NULL)
+ *Error = ErrRBLF_SelectFailed;
return -1;
}
if (FD_ISSET(*fd, &rfds) != 0) {
*Pos = pos + len + 1;
return len - rlen;
}
+ *Error = ErrRBLF_NotEnoughSentFromServer;
return -1;
}
return nRead;
}
+const char *ErrRBB_too_many_selects = "StrBufReadBLOBBuffered: to many selects; aborting.";
/**
* \brief Input binary data from socket
* flushes and closes the FD on error
}
if (nSelects > 10) {
FlushStrBuf(IOBuf);
+ *Error = ErrRBB_too_many_selects;
return -1;
}
}
}
}
+/**
+ * \Brief removes double slashes from pathnames
+ * \param Dir directory string to filter
+ * \param RemoveTrailingSlash allows / disallows trailing slashes
+ */
+void StrBufStripSlashes(StrBuf *Dir, int RemoveTrailingSlash)
+{
+ char *a, *b;
+
+ a = b = Dir->buf;
+
+ while (!IsEmptyStr(a)) {
+ if (*a == '/') {
+ while (*a == '/')
+ a++;
+ *b = '/';
+ b++;
+ }
+ else {
+ *b = *a;
+ b++; a++;
+ }
+ }
+ if ((RemoveTrailingSlash) && (*(b - 1) != '/')){
+ *b = '/';
+ b++;
+ }
+ *b = '\0';
+ Dir->BufUsed = b - Dir->buf;
+}
/**
* \brief unhide special chars hidden to the HTML escaper
char *compressed_data = NULL;
size_t compressed_len, bufsize;
int i = 0;
-
- bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
+
+ bufsize = compressed_len = Buf->BufUsed + (Buf->BufUsed / 100) + 100;
compressed_data = malloc(compressed_len);
+ if (compressed_data == NULL)
+ return -1;
/* Flush some space after the used payload so valgrind shuts up... */
while ((i < 10) && (Buf->BufUsed + i < Buf->BufSize))
Buf->buf[Buf->BufUsed + i++] = '\0';
size_t obuflen; /**< Length of output buffer */
- if (ConvertBuf->BufUsed >= TmpBuf->BufSize)
- IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed);
+ /* since we're converting to utf-8, one glyph may take up to 6 bytes */
+ if (ConvertBuf->BufUsed * 6 >= TmpBuf->BufSize)
+ IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed * 6);
TRYAGAIN:
ic = *(iconv_t*)pic;
ibuf = ConvertBuf->buf;
ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMe));
- if (start != DecodeMe->buf)
- StrBufAppendBufPlain(Target, DecodeMe->buf, start - DecodeMe->buf, 0);
+ if (start != DecodeMe->buf) {
+ long nFront;
+
+ nFront = start - DecodeMe->buf;
+ StrBufAppendBufPlain(Target, DecodeMe->buf, nFront, 0);
+ len -= nFront;
+ }
/*
* Since spammers will go to all sorts of absurd lengths to get their
* messages through, there are LOTS of corrupt headers out there.