* sbr/fmt_scan.c: Turn the PUTSF macro into a function capable of handling
[mmh] / sbr / fmt_scan.c
index 5dc7f22..4921854 100644 (file)
@@ -88,7 +88,6 @@ match (char *str, char *sub)
 /*
  * macros to format data
  */
-
 #define PUTDF(cp, num, wid, fill)\
        if (cp + wid < ep) {\
            if ((i = (num)) < 0)\
@@ -109,67 +108,42 @@ match (char *str, char *sub)
            cp += c;\
            }
 
-#define PUTD(cp, num)\
-       if (cp < ep) {\
-           if ((i = (num)) == 0)\
-               *cp++ = '0';\
-           else {\
-               if ((i = (num)) < 0) {\
-                   *cp++ = '-';\
-                   i = -(num);\
-                   }\
-               c = 10;\
-               while (c <= i) \
-                   c *= 10;\
-               while (cp < ep && c > 1) {\
-                   c /= 10;\
-                   *cp++ = (i / c) + '0';\
-                   i %= c;\
-                   }\
-               }\
-           }
+char * PUTSF(char *cp, char *str, unsigned int wid, char fill) {
+
+    unsigned int i, j;
+    unsigned int char_len;
+    unsigned int term_len = 0;
+    wchar_t wide_char;
+
+    for (i = 0 ; i < wid && i < strlen(str) && term_len < wid; ) {
+        char_len = mblen(str + i, strlen(str + i));
+        if (char_len <= 0) {
+            continue;
+        }
+        mbtowc(&wide_char, str + i, strlen(str + i));
+        term_len += wcwidth(wide_char);
+
+        for (j = 0 ; j < char_len ; j++) {
+            *(cp + i) = *(str + i);
+            i++;
+        }
+    }
 
-#ifdef LOCALE
-#define PUTSF(cp, str, wid, fill) {\
-               ljust = 0;\
-               if ((i = (wid)) < 0) {\
-                       i = -i;\
-                       ljust++;\
-               }\
-               if ((sp = (str))) {\
-                       if (ljust) {\
-                               c = strlen(sp);\
-                               if (c > i)\
-                                       sp += c - i;\
-                               else {\
-                                       while( --i >= c && cp < ep)\
-                                               *cp++ = fill;\
-                                       i++;\
-                               }\
-                       } else {\
-                           while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
-                               sp++;\
-                       }\
-                       while ((c = (unsigned char) *sp++) && --i >= 0 && cp < ep)\
-                               if (isgraph(c)) \
-                                   *cp++ = c;\
-                               else {\
-                                       while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
-                                               sp++;\
-                                           *cp++ = ' ';\
-                               }\
-               }\
-               if (!ljust)\
-               while( --i >= 0 && cp < ep)\
-                   *cp++ = fill;\
-       }
+    if (term_len < wid) {
+        for (j = term_len ; j <= wid ; j++) {
+            *(cp + i++) = fill;
+        }
+    }
+
+    return cp + i;
+}
 
 #define PUTS(cp, str) {\
                if ((sp = (str))) {\
                    while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
                        sp++;\
                    while((c = (unsigned char) *sp++) && cp < ep)\
-                       if (isgraph(c)) \
+                       if (!iscntrl(c) && !isspace(c)) \
                            *cp++ = c;\
                        else {\
                            while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
@@ -179,59 +153,6 @@ match (char *str, char *sub)
                }\
        }
 
-#else /* LOCALE */
-#define PUTSF(cp, str, wid, fill) {\
-               ljust = 0;\
-               if ((i = (wid)) < 0) {\
-                       i = -i;\
-                       ljust++;\
-               }\
-               if (sp = (str)) {\
-                       if (ljust) {\
-                               c = strlen(sp);\
-                               if (c > i)\
-                                       sp += c - i;\
-                               else {\
-                                       while( --i >= c && cp < ep)\
-                                               *cp++ = fill;\
-                                       i++;\
-                               }\
-                       } else {\
-                   while ((c = *sp) && c <= 32)\
-                       sp++;\
-                       }\
-                       while ((c = *sp++) && --i >= 0 && cp < ep)\
-                               if (c > 32) \
-                           *cp++ = c;\
-                       else {\
-                                       while ((c = *sp) && c <= 32)\
-                               sp++;\
-                           *cp++ = ' ';\
-                       }\
-               }\
-               if (!ljust)\
-               while( --i >= 0 && cp < ep)\
-                   *cp++ = fill;\
-               }
-
-#define PUTS(cp, str) {\
-               if (sp = (str)) {\
-                   while ((c = *sp) && c <= 32)\
-                       sp++;\
-                   while( (c = *sp++) && cp < ep)\
-                       if ( c > 32 ) \
-                           *cp++ = c;\
-                       else {\
-                           while ( (c = *sp) && c <= 32 )\
-                               sp++;\
-                           *cp++ = ' ';\
-                       }\
-               }\
-               }
-
-#endif /* LOCALE */
-
-
 static char *lmonth[] = { "January",  "February","March",   "April",
                          "May",      "June",    "July",    "August",
                          "September","October", "November","December" };
@@ -286,7 +207,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
     char *cp, *ep, *sp;
     char *savestr, *str = NULL;
     char buffer[BUFSIZ], buffer2[BUFSIZ];
-    int i, c, ljust;
+    int i, c, ljust, n;
     int value = 0;
     time_t t;
     struct format *fmt;
@@ -296,6 +217,15 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
 
     cp = scanl;
     ep = scanl + width - 1;
+
+    for (fmt = format; fmt->f_type != FT_DONE; fmt++)
+       switch (fmt->f_type) {
+       case FT_PARSEADDR:
+       case FT_PARSEDATE:
+           fmt->f_comp->c_flags &= ~CF_PARSED;
+           break;
+       }
+
     fmt = format;
 
     while (cp < ep) {
@@ -305,7 +235,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            PUTS (cp, fmt->f_comp->c_text);
            break;
        case FT_COMPF:
-           PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
+           cp = PUTSF(cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
            break;
 
        case FT_LIT:
@@ -331,13 +261,14 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            PUTS (cp, str);
            break;
        case FT_STRF:
-           PUTSF (cp, str, fmt->f_width, fmt->f_fill);
+           cp =PUTSF (cp, str, fmt->f_width, fmt->f_fill);
            break;
        case FT_STRFW:
            adios (NULL, "internal error (FT_STRFW)");
 
        case FT_NUM:
-           PUTD (cp, value);
+           n = snprintf(cp, ep - cp, "%d", value);
+           if (n >= 0) cp += n;
            break;
        case FT_NUMF:
            PUTDF (cp, value, fmt->f_width, fmt->f_fill);
@@ -453,14 +384,14 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            break;
 
        case FT_LS_DECODECOMP:
-           if (decode_rfc2047(fmt->f_comp->c_text, buffer2))
+           if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2)))
                str = buffer2;
            else
                str = fmt->f_comp->c_text;
            break;
 
        case FT_LS_DECODE:
-           if (str && decode_rfc2047(str, buffer2))
+           if (str && decode_rfc2047(str, buffer2, sizeof(buffer2)))
                str = buffer2;
            break;
 
@@ -469,6 +400,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                    char *xp;
 
                    strncpy(buffer, str, sizeof(buffer));
+                   buffer[sizeof(buffer)-1] = '\0';
                    str = buffer;
                    while (isspace(*str))
                            str++;
@@ -490,7 +422,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            break;
 
        case FT_LV_COMPFLAG:
-           value = fmt->f_comp->c_flags;
+           value = (fmt->f_comp->c_flags & CF_TRUE) != 0;
            break;
        case FT_LV_COMP:
            value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
@@ -502,7 +434,10 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            value = dat[fmt->f_value];
            break;
        case FT_LV_STRLEN:
-           value = strlen(str);
+           if (str != NULL)
+                   value = strlen(str);
+           else
+                   value = 0;
            break;
        case FT_LV_CHAR_LEFT:
            value = width - (cp - scanl);
@@ -654,6 +589,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            if ((str = mn->m_pers) == NULL) {
                if ((str = mn->m_note)) {
                    strncpy (buffer, str, sizeof(buffer));
+                   buffer[sizeof(buffer)-1] = '\0';
                    str = buffer;
                    if (*str == '(')
                        str++;
@@ -690,6 +626,40 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                  }
                }
            }
+           break;  
+
+
+               /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
+       case FT_LS_UNQUOTE:
+           if (str) {          
+               int m;
+               strncpy(buffer, str, sizeof(buffer));
+               /* strncpy doesn't NUL-terminate if it fills the buffer */
+               buffer[sizeof(buffer)-1] = '\0';
+               str = buffer;
+       
+               /* we will parse from buffer to buffer2 */
+               n = 0; /* n is the input position in str */
+               m = 0; /* m is the ouput position in buffer2 */
+
+               while ( str[n] != '\0') {
+                   switch ( str[n] ) {
+                       case '\\':
+                           n++;
+                           if ( str[n] != '\0') 
+                               buffer2[m++] = str[n++];
+                           break;
+                       case '"':
+                           n++;
+                           break;
+                       default:
+                           buffer2[m++] = str[n++];
+                           break;
+                       }                
+               }
+               buffer2[m] = '\0';
+               str = buffer2;
+            }
            break;
 
        case FT_LOCALDATE:
@@ -710,13 +680,16 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
 
        case FT_PARSEDATE:
            comp = fmt->f_comp;
+           if (comp->c_flags & CF_PARSED)
+               break;
            if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
                *comp->c_tws = *tws;
-               comp->c_flags = 0;
-           } else if (comp->c_flags >= 0) {
+               comp->c_flags &= ~CF_TRUE;
+           } else if ((comp->c_flags & CF_DATEFAB) == 0) {
                memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
-               comp->c_flags = 1;
+               comp->c_flags = CF_TRUE;
            }
+           comp->c_flags |= CF_PARSED;
            break;
 
        case FT_FORMATADDR:
@@ -779,6 +752,8 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
 
        case FT_PARSEADDR:
            comp = fmt->f_comp;
+           if (comp->c_flags & CF_PARSED)
+               break;
            if (comp->c_mn != &fmt_mnull)
                mnfree (comp->c_mn);
            if ((sp = comp->c_text) && (sp = getname(sp)) &&
@@ -786,6 +761,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                comp->c_mn = mn;
                while (getname(""))
                    ;
+               comp->c_flags |= CF_PARSED;
            } else {
                while (getname(""))             /* XXX */
                    ;
@@ -805,15 +781,22 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
            if ((sp = comp->c_text) && (sp = getname(sp)) &&
                (mn = getm (sp, NULL, 0, AD_NAME, NULL))) {
                comp->c_mn = mn;
-               comp->c_flags = ismymbox(mn);
+               if (ismymbox(mn))
+                   comp->c_flags |= CF_TRUE;
+               else
+                   comp->c_flags &= ~CF_TRUE;
                while ((sp = getname(sp)))
-                   if (comp->c_flags == 0 &&
+                   if ((comp->c_flags & CF_TRUE) == 0 &&
                        (mn = getm (sp, NULL, 0, AD_NAME, NULL)))
-                       comp->c_flags |= ismymbox(mn);
+                       if (ismymbox(mn))
+                           comp->c_flags |= CF_TRUE;
            } else {
                while (getname(""))             /* XXX */
                    ;
-               comp->c_flags = (comp->c_text == 0);
+               if (comp->c_text == 0)
+                   comp->c_flags |= CF_TRUE;
+               else
+                   comp->c_flags &= ~CF_TRUE;
                comp->c_mn = &fmt_mnull;
            }
            break;