]> code.citadel.org Git - citadel.git/blobdiff - libcitadel/lib/stringbuf.c
* StrBufReplaceToken(): source and dest of move operation was wrong
[citadel.git] / libcitadel / lib / stringbuf.c
index 400fddbfc0f5b6b7a1512e6d4932c63e6e4de711..be4da4eb4e90c6b3cbf48fd70c098d3b2500be7a 100644 (file)
@@ -293,7 +293,7 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
  */
 void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
 {
-       if (Buf->BufUsed > ThreshHold) {
+       if ((Buf != NULL) && (Buf->BufUsed > ThreshHold)) {
                free(Buf->buf);
                Buf->buf = (char*) malloc(NewSize);
                Buf->BufUsed = 0;
@@ -310,6 +310,8 @@ void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
  */
 long StrBufShrinkToFit(StrBuf *Buf, int Force)
 {
+       if (Buf == NULL)
+               return -1;
        if (Force || 
            (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
        {
@@ -616,8 +618,9 @@ int StrBufIsNumber(const StrBuf *Buf) {
                return 0;
        return 0;
 } 
+
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief modifies a Single char of the Buf
  * You can point to it via char* or a zero-based integer
  * @param Buf The buffer to manipulate
@@ -638,7 +641,34 @@ long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
 }
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
+ * @brief modifies a range of chars of the Buf
+ * You can point to it via char* or a zero-based integer
+ * @param Buf The buffer to manipulate
+ * @param ptr char* to zero; use NULL if unused
+ * @param nThChar zero based pointer into the string; use -1 if unused
+ * @param nChars how many chars are to be flushed?
+ * @param PookValue The Character to place into that area
+ */
+long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue)
+{
+       if (Buf == NULL)
+               return -1;
+       if (ptr != NULL)
+               nThChar = ptr - Buf->buf;
+       if ((nThChar < 0) || (nThChar > Buf->BufUsed))
+               return -1;
+       if (nThChar + nChars > Buf->BufUsed)
+               nChars =  Buf->BufUsed - nThChar;
+
+       memset(Buf->buf + nThChar, PookValue, nChars);
+       /* just to be shure... */
+       Buf->buf[Buf->BufUsed] = 0;
+       return nChars;
+}
+
+/**
+ * @ingroup StrBuf_Filler
  * @brief Append a StringBuffer to the buffer
  * @param Buf Buffer to modify
  * @param AppendBuf Buffer to copy at the end of our buffer
@@ -663,7 +693,7 @@ void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset)
 
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief Append a C-String to the buffer
  * @param Buf Buffer to modify
  * @param AppendBuf Buffer to copy at the end of our buffer
@@ -695,7 +725,7 @@ void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, u
 }
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief sprintf like function appending the formated string to the buffer
  * vsnprintf version to wrap into own calls
  * @param Buf Buffer to extend by format and Params
@@ -738,7 +768,7 @@ void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
 }
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief sprintf like function appending the formated string to the buffer
  * @param Buf Buffer to extend by format and Params
  * @param format printf alike format to add
@@ -779,7 +809,7 @@ void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
 }
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief sprintf like function putting the formated string into the buffer
  * @param Buf Buffer to extend by format and Parameters
  * @param format printf alike format to add
@@ -807,7 +837,7 @@ void StrBufPrintf(StrBuf *Buf, const char *format, ...)
 }
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief Callback for cURL to append the webserver reply to a buffer
  * @param ptr pre-defined by the cURL API; see man 3 curl for mre info
  * @param size pre-defined by the cURL API; see man 3 curl for mre info
@@ -842,7 +872,8 @@ int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t n
        size_t NCharsRemain;
        if (Offset > Source->BufUsed)
        {
-               FlushStrBuf(dest);
+               if (dest != NULL)
+                       FlushStrBuf(dest);
                return 0;
        }
        if (Offset + nChars < Source->BufUsed)
@@ -929,20 +960,51 @@ void StrBufTrim(StrBuf *Buf)
        int delta = 0;
        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
 
+       while ((Buf->BufUsed > 0) &&
+              isspace(Buf->buf[Buf->BufUsed - 1]))
+       {
+               Buf->BufUsed --;
+       }
+       Buf->buf[Buf->BufUsed] = '\0';
+
+       if (Buf->BufUsed == 0) return;
+
        while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){
                delta ++;
        }
        if (delta > 0) StrBufCutLeft(Buf, delta);
+}
 
-       if (Buf->BufUsed == 0) return;
-       while (isspace(Buf->buf[Buf->BufUsed - 1])){
-               Buf->BufUsed --;
+void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
+{
+       const char *pBuff;
+       const char *pLeft;
+       const char *pRight;
+
+       if (Buf == NULL)
+               return;
+       pLeft = pBuff = Buf->buf;
+       while (pBuff != NULL) {
+               pLeft = pBuff;
+               pBuff = strchr(pBuff, leftboundary);
+               if (pBuff != NULL)
+                       pBuff++;
        }
-       Buf->buf[Buf->BufUsed] = '\0';
+               
+       if (pLeft != NULL)
+               pBuff = pLeft;
+       else
+               pBuff = Buf->buf;
+       pRight = strchr(pBuff, rightboundary);
+       if (pRight != NULL)
+               StrBufCutAt(Buf, 0, pRight);
+       if (pLeft != NULL)
+               StrBufCutLeft(Buf, pLeft - Buf->buf);
 }
 
+
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief uppercase the contents of a buffer
  * @param Buf the buffer to translate
  */
@@ -962,7 +1024,7 @@ void StrBufUpCase(StrBuf *Buf)
 
 
 /**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
  * @brief lowercase the contents of a buffer
  * @param Buf the buffer to translate
  */
@@ -985,6 +1047,41 @@ void StrBufLowerCase(StrBuf *Buf)
  *           a tokenizer that kills, maims, and destroys                       *
  *******************************************************************************/
 
+/**
+ * @ingroup StrBuf_Tokenizer
+ * @brief Replace a token at a given place with a given length by another token with given length
+ * @param Buf String where to work on
+ * @param where where inside of the Buf is the search-token
+ * @param HowLong How long is the token to be replaced
+ * @param Repl Token to insert at 'where'
+ * @param ReplLen Length of repl
+ * @returns -1 if fail else length of resulting Buf
+ */
+int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong, 
+                      const char *Repl, long ReplLen)
+{
+
+       if ((Buf == NULL) || 
+           (where > Buf->BufUsed) ||
+           (where + HowLong > Buf->BufUsed))
+               return -1;
+
+       if (where + ReplLen - HowLong > Buf->BufSize)
+               if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0)
+                       return -1;
+
+       memmove(Buf->buf + where + ReplLen, 
+               Buf->buf + where + HowLong,
+               Buf->BufUsed - where - HowLong);
+                                               
+       memcpy(Buf->buf + where, 
+              Repl, ReplLen);
+
+       Buf->BufUsed += ReplLen - HowLong;
+
+       return Buf->BufUsed;
+}
+
 /**
  * @ingroup StrBuf_Tokenizer
  * @brief Counts the numbmer of tokens in a buffer
@@ -1543,8 +1640,7 @@ void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
                   (*pch >= '@' && *pch <= 'Z') || /* @ A-Z */
                   (*pch >= '0' && *pch <= ':') || /* 0-9 : */
                   (*pch == '!') || (*pch == '_') || 
-                  (*pch == ',') || (*pch == '.') || 
-                  (*pch == ','))
+                  (*pch == ',') || (*pch == '.'))
                {
                        *(pt++) = *(pch++);
                        OutBuf->BufUsed++;
@@ -1561,6 +1657,53 @@ void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
        *pt = '\0';
 }
 
+/** 
+ * @ingroup StrBuf_DeEnCoder
+ * @brief append a string in hex encoding to the buffer
+ * @param OutBuf the output buffer
+ * @param In Buffer to encode
+ * @param PlainIn way in from plain old c strings
+ */
+void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
+{
+       const char *pch, *pche;
+       char *pt, *pte;
+       int len;
+       
+       if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+               return;
+       if (PlainIn != NULL) {
+               len = strlen(PlainIn);
+               pch = PlainIn;
+               pche = pch + len;
+       }
+       else {
+               pch = In->buf;
+               pche = pch + In->BufUsed;
+               len = In->BufUsed;
+       }
+
+       if (len == 0) 
+               return;
+
+       pt = OutBuf->buf + OutBuf->BufUsed;
+       pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
+
+       while (pch < pche) {
+               if (pt >= pte) {
+                       IncreaseBuf(OutBuf, 1, -1);
+                       pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
+                       pt = OutBuf->buf + OutBuf->BufUsed;
+               }
+
+               *pt = HexList[(unsigned char)*pch][0];
+               pt ++;
+               *pt = HexList[(unsigned char)*pch][1];
+               pt ++; pch ++; OutBuf->BufUsed += 2;
+       }
+       *pt = '\0';
+}
+
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief Append a string, escaping characters which have meaning in HTML.  
@@ -2174,6 +2317,9 @@ long StrBufUnescape(StrBuf *Buf, int StripBlanks)
        char hex[3];
        long len;
 
+       if (Buf == NULL)
+               return -1;
+
        while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
                Buf->buf[Buf->BufUsed - 1] = '\0';
                Buf->BufUsed --;
@@ -2297,6 +2443,36 @@ void StrBufReplaceChars(StrBuf *buf, char search, char replace)
 
 }
 
+/**
+ * @ingroup StrBuf
+ * @brief removes all \r s from the string, or replaces them with \n if its not a combination of both.
+ * @param buf Buffer to modify
+ */
+void StrBufToUnixLF(StrBuf *buf)
+{
+       char *pche, *pchS, *pchT;
+       if (buf == NULL)
+               return;
+
+       pche = buf->buf + buf->BufUsed;
+       pchS = pchT = buf->buf;
+       while (pchS < pche)
+       {
+               if (*pchS == '\r')
+               {
+                       pchS ++;
+                       if (*pchS != '\n') {
+                               *pchT = '\n';
+                               pchT++;
+                       }
+               }
+               *pchT = *pchS;
+               pchT++; pchS++;
+       }
+       *pchT = '\0';
+       buf->BufUsed = pchT - buf->buf;
+}
+
 
 /*******************************************************************************
  *                 Iconv Wrapper; RFC822 de/encoding                           *
@@ -2338,9 +2514,9 @@ void  ctdl_iconv_open(const char *tocode, const char *fromcode, void *pic)
  * @param bptr where to start searching
  * @returns found position, NULL if none.
  */
-static inline char *FindNextEnd (const StrBuf *Buf, char *bptr)
+static inline const char *FindNextEnd (const StrBuf *Buf, const char *bptr)
 {
-       char * end;
+       const char * end;
        /* Find the next ?Q? */
        if (Buf->BufUsed - (bptr - Buf->buf)  < 6)
                return NULL;
@@ -2454,8 +2630,8 @@ TRYAGAIN:
  */
 inline static void DecodeSegment(StrBuf *Target, 
                                 const StrBuf *DecodeMe, 
-                                char *SegmentStart, 
-                                char *SegmentEnd, 
+                                const char *SegmentStart, 
+                                const char *SegmentEnd, 
                                 StrBuf *ConvertBuf,
                                 StrBuf *ConvertBuf2, 
                                 StrBuf *FoundCharset)
@@ -2471,7 +2647,7 @@ inline static void DecodeSegment(StrBuf *Target,
        /* Now we handle foreign character sets properly encoded
         * in RFC2047 format.
         */
-       StaticBuf.buf = SegmentStart;
+       StaticBuf.buf = (char*) SegmentStart; /*< it will just be read there... */
        StaticBuf.BufUsed = SegmentEnd - SegmentStart;
        StaticBuf.BufSize = DecodeMe->BufSize - (SegmentStart - DecodeMe->buf);
        extract_token(charset, SegmentStart, 1, '?', sizeof charset);
@@ -2537,13 +2713,13 @@ void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf*
        StrBuf *DecodedInvalidBuf = NULL;
        StrBuf *ConvertBuf, *ConvertBuf2;
        const StrBuf *DecodeMee = DecodeMe;
-       char *start, *end, *next, *nextend, *ptr = NULL;
+       const char *start, *end, *next, *nextend, *ptr = NULL;
 #ifdef HAVE_ICONV
        iconv_t ic = (iconv_t)(-1) ;
 #endif
        const char *eptr;
        int passes = 0;
-       int i, len, delta;
+       int i, len;
        int illegal_non_rfc2047_encoding = 0;
 
        /* Sometimes, badly formed messages contain strings which were simply
@@ -2640,22 +2816,16 @@ void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf*
                                (*ptr == '\n') || 
                                (*ptr == '\t')))
                                ptr ++;
-                       /* did we find a gab just filled with blanks? */
-                       if (ptr == next)
+                       /* 
+                        * did we find a gab just filled with blanks?
+                        * if not, copy its stuff over.
+                        */
+                       if (ptr != next)
                        {
-                               long gap = next - start;
-                               memmove (end + 2,
-                                        next,
-                                        len - (gap));
-                               len -= gap;
-                               /* now terminate the gab at the end */
-                               delta = (next - end) - 2; ////TODO: const! 
-                               ((StrBuf*)DecodeMee)->BufUsed -= delta;
-                               ((StrBuf*)DecodeMee)->buf[DecodeMee->BufUsed] = '\0';
-
-                               /* move next to its new location. */
-                               next -= delta;
-                               nextend -= delta;
+                               StrBufAppendBufPlain(Target, 
+                                                    end + 2, 
+                                                    next - end - 2,
+                                                    0);
                        }
                }
                /* our next-pair is our new first pair now. */
@@ -3058,14 +3228,14 @@ static const char *ErrRBLF_NotEnoughSentFromServer="StrBufTCP_read_buffered_line
  * @ingroup StrBuf_BufferedIO
  * @brief Read a line from socket
  * flushes and closes the FD on error
- * @param Line Line to read from the fd / I/O Buffer
- * @param IOBuf the buffer to get the input to
- * @param Pos pointer to the current read position, should be NULL initialized!
+ * @param Line where to append our Line read from the fd / I/O Buffer; 
+ * @param IOBuf the buffer to get the input to; lifetime pair to FD
+ * @param Pos pointer to the current read position, should be NULL initialized on opening the FD it belongs to.!
  * @param fd pointer to the filedescriptor to read
  * @param timeout number of successless selects until we bail out
  * @param selectresolution how long to wait on each select
  * @param Error strerror() on error 
- * @returns numbers of chars read
+ * @returns numbers of chars read or -1 in case of error. "\n" will become 0
  */
 int StrBufTCP_read_buffered_line_fast(StrBuf *Line, 
                                      StrBuf *IOBuf, 
@@ -3077,7 +3247,8 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
 {
        const char *pche = NULL;
        const char *pos = NULL;
-       int len, rlen;
+       const char *pLF;
+       int len, rlen, retlen;
        int nSuccessLess = 0;
        fd_set rfds;
        const char *pch = NULL;
@@ -3085,6 +3256,7 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
        int IsNonBlock;
        struct timeval tv;
        
+       retlen = 0;
        if ((Line == NULL) ||
            (Pos == NULL) ||
            (IOBuf == NULL) ||
@@ -3101,44 +3273,72 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
            (pos != NULL) && 
            (pos < IOBuf->buf + IOBuf->BufUsed)) 
        {
+               char *pcht;
+
                pche = IOBuf->buf + IOBuf->BufUsed;
                pch = pos;
+               pcht = Line->buf;
+
                while ((pch < pche) && (*pch != '\n'))
-                       pch ++;
+               {
+                       if (Line->BufUsed + 10 > Line->BufSize)
+                       {
+                               long apos;
+                               apos = pcht - Line->buf;
+                               *pcht = '\0';
+                               IncreaseBuf(Line, 1, -1);
+                               pcht = Line->buf + apos;
+                       }
+                       *pcht++ = *pch++;
+                       Line->BufUsed++;
+                       retlen++;
+               }
+
+               len = pch - pos;
+               if (len > 0 && (*(pch - 1) == '\r') )
+               {
+                       retlen--;
+                       len --;
+                       pcht --;
+                       Line->BufUsed --;
+               }
+               *pcht = '\0';
+
                if ((pch >= pche) || (*pch == '\0'))
+               {
+                       FlushStrBuf(IOBuf);
+                       *Pos = NULL;
                        pch = NULL;
+                       pos = 0;
+               }
+
                if ((pch != NULL) && 
                    (pch <= pche)) 
                {
-                       rlen = 0;
-                       len = pch - pos;
-                       if (len > 0 && (*(pch - 1) == '\r') )
-                               rlen ++;
-                       StrBufSub(Line, IOBuf, (pos - IOBuf->buf), len - rlen);
-                       *Pos = pch + 1;
-                       return len - rlen;
+                       if (pch + 1 >= pche) {
+                               *Pos = NULL;
+                               FlushStrBuf(IOBuf);
+                       }
+                       else
+                               *Pos = pch + 1;
+                       
+                       return retlen;
                }
-       }
-       
-       if (pos != NULL) {
-               if (pos > pche)
-                       FlushStrBuf(IOBuf);
                else 
-                       StrBufCutLeft(IOBuf, (pos - IOBuf->buf));
-               *Pos = NULL;
+                       FlushStrBuf(IOBuf);
        }
+
+       /* If we come here, Pos is Unset since we read everything into Line, and now go for more. */
        
-       if (IOBuf->BufSize - IOBuf->BufUsed < 10) {
+       if (IOBuf->BufSize - IOBuf->BufUsed < 10)
                IncreaseBuf(IOBuf, 1, -1);
-               *Pos = NULL;
-       }
 
        fdflags = fcntl(*fd, F_GETFL);
        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
 
-       pch = NULL;
+       pLF = NULL;
        while ((nSuccessLess < timeout) && 
-              (pch == NULL) &&
+              (pLF == NULL) &&
               (*fd != -1)) {
                if (IsNonBlock)
                {
@@ -3171,31 +3371,43 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
                }
                else if (rlen > 0) {
                        nSuccessLess = 0;
+                       pLF = IOBuf->buf + IOBuf->BufUsed;
                        IOBuf->BufUsed += rlen;
                        IOBuf->buf[IOBuf->BufUsed] = '\0';
-                       if (IOBuf->BufUsed + 10 > IOBuf->BufSize) {
-                               IncreaseBuf(IOBuf, 1, -1);
-                               *Pos = NULL;
-                       }
                        
                        pche = IOBuf->buf + IOBuf->BufUsed;
-                       pch = IOBuf->buf;
-                       while ((pch < pche) && (*pch != '\n'))
-                               pch ++;
-                       if ((pch >= pche) || (*pch == '\0'))
-                               pch = NULL;
+                       
+                       while ((pLF < pche) && (*pLF != '\n'))
+                               pLF ++;
+                       if ((pLF >= pche) || (*pLF == '\0'))
+                               pLF = NULL;
+
+                       if (IOBuf->BufUsed + 10 > IOBuf->BufSize)
+                       {
+                               long apos;
+
+                               if (pLF != NULL) apos = pLF - IOBuf->buf;
+                               IncreaseBuf(IOBuf, 1, -1);      
+                               if (pLF != NULL) pLF = IOBuf->buf + apos;
+                       }
+
                        continue;
                }
        }
-       if (pch != NULL) {
+       *Pos = NULL;
+       if (pLF != NULL) {
                pos = IOBuf->buf;
-               rlen = 0;
-               len = pch - pos;
-               if (len > 0 && (*(pch - 1) == '\r') )
-                       rlen ++;
-               StrBufSub(Line, IOBuf, 0, len - rlen);
-               *Pos = pos + len + 1;
-               return len - rlen;
+               len = pLF - pos;
+               if (len > 0 && (*(pLF - 1) == '\r') )
+                       len --;
+               StrBufAppendBufPlain(Line, ChrPtr(IOBuf), len, 0);
+               if (pLF + 1 >= IOBuf->buf + IOBuf->BufUsed)
+               {
+                       FlushStrBuf(IOBuf);
+               }
+               else 
+                       *Pos = pLF + 1;
+               return retlen + len;
        }
        *Error = ErrRBLF_NotEnoughSentFromServer;
        return -1;
@@ -3338,7 +3550,7 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
        
        pos = *Pos;
 
-       if (pos > 0)
+       if (pos != NULL)
                len = pos - IOBuf->buf;
        rlen = IOBuf->BufUsed - len;