[svn] r6434 - in trunk/rpms: alpine collectd perl-Algorithm-Cluster
perl-Algorithm-MedianSelect-XS perl-Alien-wxWidgets testdisk
packagers at lists.rpmforge.net
packagers at lists.rpmforge.net
Thu Jul 31 02:54:18 CEST 2008
Author: dag
Date: 2008-07-31 01:54:17 +0100 (Thu, 31 Jul 2008)
New Revision: 6434
Added:
trunk/rpms/alpine/alpine-1.10-fillpara.patch
trunk/rpms/alpine/alpine-1.10-maildir.patch
trunk/rpms/alpine/alpine-1.10-rules.patch
trunk/rpms/alpine/alpine-1.10-select-bold-x.patch
Modified:
trunk/rpms/alpine/alpine.spec
trunk/rpms/collectd/collectd.spec
trunk/rpms/perl-Algorithm-Cluster/perl-Algorithm-Cluster.spec
trunk/rpms/perl-Algorithm-MedianSelect-XS/perl-Algorithm-MedianSelect-XS.spec
trunk/rpms/perl-Alien-wxWidgets/perl-Alien-wxWidgets.spec
trunk/rpms/testdisk/testdisk.spec
Log:
Updates
Added: trunk/rpms/alpine/alpine-1.10-fillpara.patch
===================================================================
--- trunk/rpms/alpine/alpine-1.10-fillpara.patch (rev 0)
+++ trunk/rpms/alpine/alpine-1.10-fillpara.patch 2008-07-31 00:54:17 UTC (rev 6434)
@@ -0,0 +1,3930 @@
+diff -rc alpine-1.10/alpine/mailview.c alpine-1.10.fillpara/alpine/mailview.c
+*** alpine-1.10/alpine/mailview.c 2008-03-03 13:37:30.000000000 -0800
+--- alpine-1.10.fillpara/alpine/mailview.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 205,211 ****
+--- 205,219 ----
+ int pcpine_view_cursor(int, long);
+ #endif
+
++ static char *prefix;
++ #define NO_FLOWED 0x0000
++ #define IS_FLOWED 0x0001
++ #define DELETEQUO 0x0010
++ #define COLORAQUO 0x0100
++ #define RAWSTRING 0x1000
+
++ int is_word (char *, int, int);
++ int is_mailbox(char *, int, int);
+
+ /*----------------------------------------------------------------------
+ Format a buffer with the text of the current message for browser
+***************
+*** 296,301 ****
+--- 304,320 ----
+ else
+ ps->unseen_in_view = !mc->seen;
+
++ prefix = reply_quote_str(env);
++ /* Make sure the prefix is not only made of spaces, so that we do not
++ * paint the screen incorrectly
++ */
++ if (prefix && *prefix){
++ int i;
++ for (i = 0; isspace((unsigned char) prefix[i]); i++);
++ if (i == strlen(prefix))
++ fs_give((void **)&prefix);
++ }
++
+ init_handles(&handles);
+
+ store = so_get(src, NULL, EDIT_ACCESS);
+***************
+*** 459,464 ****
+--- 478,485 ----
+ }
+ while(ps->next_screen == SCREEN_FUN_NULL);
+
++ if (prefix && *prefix)
++ fs_give((void **)&prefix);
+ if(we_cancel)
+ cancel_busy_cue(-1);
+
+diff -rc alpine-1.10/pico/basic.c alpine-1.10.fillpara/pico/basic.c
+*** alpine-1.10/pico/basic.c 2007-11-26 15:45:22.000000000 -0800
+--- alpine-1.10.fillpara/pico/basic.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 25,33 ****
+ * framing, are hard.
+ */
+ #include "headers.h"
+!
+ #include "osdep/terminal.h"
+
+
+ /*
+ * Move the cursor to the
+--- 25,34 ----
+ * framing, are hard.
+ */
+ #include "headers.h"
+! #include "../pith/osdep/color.h"
+ #include "osdep/terminal.h"
+
++ int indent_match(char *, LINE *, char *, int, int);
+
+ /*
+ * Move the cursor to the
+***************
+*** 284,290 ****
+ gotobop(int f, int n)
+ {
+ int quoted, qlen;
+! UCS qstr[NLINE], qstr2[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+--- 285,291 ----
+ gotobop(int f, int n)
+ {
+ int quoted, qlen;
+! char qstr[NLINE], qstr2[NLINE], ind_str[NLINE], pqstr[NLINE];;
+
+ if (n < 0) /* the other way...*/
+ return(gotoeop(f, -n));
+***************
+*** 296,301 ****
+--- 297,310 ----
+ curwp->w_dotp = lback(curwp->w_dotp);
+ curwp->w_doto = 0;
+ }
++
++ if (indent_match(default_qstr(), curwp->w_dotp,ind_str, NLINE, 0)){
++ if (n){ /* look for another paragraph ? */
++ curwp->w_dotp = lback(curwp->w_dotp);
++ continue;
++ }
++ break;
++ }
+
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+***************
+*** 303,322 ****
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! quoted = glo_quote_str ? quote_match(glo_quote_str, curwp->w_dotp, qstr, NLINE) : 0;
+! qlen = quoted ? ucs4_strlen(qstr) : 0;
+ while(lback(curwp->w_dotp) != curbp->b_linep
+ && llength(lback(curwp->w_dotp)) > qlen
+! && (glo_quote_str
+! ? (quoted == quote_match(glo_quote_str,
+! lback(curwp->w_dotp),
+! qstr2, NLINE)
+! && !ucs4_strcmp(qstr, qstr2))
+! : 1)
+ && lgetc(curwp->w_dotp, qlen).c != TAB
+ && lgetc(curwp->w_dotp, qlen).c != ' ')
+ curwp->w_dotp = lback(curwp->w_dotp);
+
+ if(n){
+ /* keep looking */
+ if(lback(curwp->w_dotp) == curbp->b_linep)
+--- 312,371 ----
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 0);
+! qlen = quoted ? strlen(qstr) : 0;
+ while(lback(curwp->w_dotp) != curbp->b_linep
+ && llength(lback(curwp->w_dotp)) > qlen
+! && (quoted == quote_match(default_qstr(),
+! lback(curwp->w_dotp), qstr2, NLINE, 0))
+! && !strcmp(qstr, qstr2) /* processed string */
+! && (quoted == quote_match(default_qstr(),
+! lback(curwp->w_dotp), qstr2, NLINE, 1))
+! && !strcmp(qstr, qstr2) /* raw string */
+! && !indent_match(default_qstr(),
+! lback(curwp->w_dotp),ind_str, NLINE, 0)
+ && lgetc(curwp->w_dotp, qlen).c != TAB
+ && lgetc(curwp->w_dotp, qlen).c != ' ')
+ curwp->w_dotp = lback(curwp->w_dotp);
+
++ /*
++ * Ok, we made it here and we assume that we are at the begining
++ * of the paragraph. Let's double check this now. In order to do
++ * so we shell check if the first line was indented in a special
++ * way.
++ */
++ if(lback(curwp->w_dotp) == curbp->b_linep)
++ break;
++ else{
++ int i, j;
++
++ /*
++ * First we test if the preceding line is indented.
++ * for the following test we need to have the raw values,
++ * not the processed values
++ */
++ quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1);
++ quote_match(default_qstr(), lback(curwp->w_dotp), qstr2, NLINE, 1);
++ for (i = 0, j = 0;
++ qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]); i++, j++);
++ for (; ISspace(qstr2[i]); i++);
++ for (; ISspace(qstr[j]); j++);
++ if ((indent_match(default_qstr(), lback(curwp->w_dotp),
++ ind_str, NLINE, 1)
++ && (strlenis(qstr2)
++ + strlenis(ind_str) >= strlenis(qstr)))
++ || (lback(curwp->w_dotp) != curbp->b_linep
++ && llength(lback(curwp->w_dotp)) > qlen
++ && (quoted == quote_match(default_qstr(),
++ lback(curwp->w_dotp), pqstr, NLINE, 0))
++ && !strcmp(qstr, pqstr)
++ && lgetc(curwp->w_dotp, qlen).c != TAB
++ && lgetc(curwp->w_dotp, qlen).c != ' '
++ && (strlenis(qstr2) > strlenis(qstr)))
++ && !qstr2[i] && !qstr[j])
++ curwp->w_dotp = lback(curwp->w_dotp);
++ }
++
+ if(n){
+ /* keep looking */
+ if(lback(curwp->w_dotp) == curbp->b_linep)
+***************
+*** 329,335 ****
+ else{
+ /* leave cursor on first word in para */
+ curwp->w_doto = 0;
+! while(ucs4_isspace(lgetc(curwp->w_dotp, curwp->w_doto).c))
+ if(++curwp->w_doto >= llength(curwp->w_dotp)){
+ curwp->w_doto = 0;
+ curwp->w_dotp = lforw(curwp->w_dotp);
+--- 378,384 ----
+ else{
+ /* leave cursor on first word in para */
+ curwp->w_doto = 0;
+! while(ISspace(lgetc(curwp->w_dotp, curwp->w_doto).c))
+ if(++curwp->w_doto >= llength(curwp->w_dotp)){
+ curwp->w_doto = 0;
+ curwp->w_dotp = lforw(curwp->w_dotp);
+***************
+*** 352,359 ****
+ int
+ gotoeop(int f, int n)
+ {
+! int quoted, qlen;
+! UCS qstr[NLINE], qstr2[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+--- 401,409 ----
+ int
+ gotoeop(int f, int n)
+ {
+! int quoted, qlen, indented, changeqstr = 0;
+! int i,j, fli = 0; /* fli = first line indented a boolean variable */
+! char qstr[NLINE], qstr2[NLINE], ind_str[NLINE];
+
+ if (n < 0) /* the other way...*/
+ return(gotobop(f, -n));
+***************
+*** 366,390 ****
+ break;
+ }
+
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ *
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! quoted = glo_quote_str
+! ? quote_match(glo_quote_str,
+! curwp->w_dotp, qstr, NLINE) : 0;
+! qlen = quoted ? ucs4_strlen(qstr) : 0;
+
+ while(curwp->w_dotp != curbp->b_linep
+ && llength(lforw(curwp->w_dotp)) > qlen
+! && (glo_quote_str
+! ? (quoted == quote_match(glo_quote_str,
+! lforw(curwp->w_dotp),
+! qstr2, NLINE)
+! && !ucs4_strcmp(qstr, qstr2))
+! : 1)
+ && lgetc(lforw(curwp->w_dotp), qlen).c != TAB
+ && lgetc(lforw(curwp->w_dotp), qlen).c != ' ')
+ curwp->w_dotp = lforw(curwp->w_dotp);
+--- 416,484 ----
+ break;
+ }
+
++ /*
++ * We need to figure out if this line is the first line of
++ * a paragraph that has been indented in a special way. If this
++ * is the case, we advance one more line before we use the
++ * algorithm below
++ */
++
++ if(curwp->w_dotp != curbp->b_linep){
++ quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, 1);
++ quote_match(default_qstr(), lforw(curwp->w_dotp), qstr2, NLINE, 1);
++ indented = indent_match(default_qstr(), curwp->w_dotp, ind_str,
++ NLINE, 1);
++ if (strlenis(qstr)
++ + strlenis(ind_str) < strlenis(qstr2)){
++ curwp->w_doto = llength(curwp->w_dotp);
++ if(n){ /* this line is a paragraph by itself */
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ continue;
++ }
++ break;
++ }
++ for (i=0,j=0; qstr[i] && qstr2[i] && (qstr[i] == qstr2[i]);i++,j++);
++ for (; ISspace(qstr[i]); i++);
++ for (; ISspace(qstr2[j]); j++);
++ if (!qstr[i] && !qstr2[j] && indented){
++ fli++;
++ if (indent_match(default_qstr(), lforw(curwp->w_dotp),
++ ind_str, NLINE, 0)){
++ if (n){ /* look for another paragraph ? */
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ continue;
++ }
++ }
++ else{
++ if (!lisblank(lforw(curwp->w_dotp)))
++ curwp->w_dotp = lforw(curwp->w_dotp);
++ }
++ }
++ }
++
+ /* scan line by line until we come to a line ending with
+ * a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ *
+ * PLUS: if there's a quote string, a quoted-to-non-quoted
+ * line transition.
+ */
+! /* if the first line is indented (fli == 1), then the test below
+! is on the second line, and in that case we will need the raw
+! string, not the processed string
+! */
+! quoted = quote_match(default_qstr(), curwp->w_dotp, qstr, NLINE, fli);
+! qlen = quoted ? strlen(qstr) : 0;
+
+ while(curwp->w_dotp != curbp->b_linep
+ && llength(lforw(curwp->w_dotp)) > qlen
+! && (quoted == quote_match(default_qstr(),
+! lforw(curwp->w_dotp), qstr2, NLINE, fli))
+! && !strcmp(qstr, qstr2)
+! && (quoted == quote_match(default_qstr(),
+! lforw(curwp->w_dotp), qstr2, NLINE, 1))
+! && !strcmp(qstr, qstr2)
+! && !indent_match(default_qstr(),
+! lforw(curwp->w_dotp), ind_str, NLINE, 0)
+ && lgetc(lforw(curwp->w_dotp), qlen).c != TAB
+ && lgetc(lforw(curwp->w_dotp), qlen).c != ' ')
+ curwp->w_dotp = lforw(curwp->w_dotp);
+diff -rc alpine-1.10/pico/efunc.h alpine-1.10.fillpara/pico/efunc.h
+*** alpine-1.10/pico/efunc.h 2007-11-06 15:51:13.000000000 -0800
+--- alpine-1.10.fillpara/pico/efunc.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 248,257 ****
+ extern int fillpara(int, int);
+ extern int fillbuf(int, int);
+ extern int inword(void);
+! extern int quote_match(UCS *, LINE *, UCS *, size_t);
+ extern int ucs4_isalnum(UCS);
+ extern int ucs4_isalpha(UCS);
+ extern int ucs4_isspace(UCS);
+ extern int ucs4_ispunct(UCS);
+
+ #endif /* EFUNC_H */
+--- 248,264 ----
+ extern int fillpara(int, int);
+ extern int fillbuf(int, int);
+ extern int inword(void);
+! extern int quote_match(char *, LINE *, char *, size_t, int);
+! extern char *default_qstr(void);
+! extern void flatten_qstring(QSTRING_S *, char *, int);
+! extern void free_qs(QSTRING_S **);
+! extern QSTRING_S *do_quote_match (char *, char *, char *, char *, char *, int, int);
+! extern QSTRING_S *do_raw_quote_match(char *, char *, char *, char *, QSTRING_S **, QSTRING_S **);
+! extern int indent_match(char *, LINE *, char *, int, int);
+ extern int ucs4_isalnum(UCS);
+ extern int ucs4_isalpha(UCS);
+ extern int ucs4_isspace(UCS);
+ extern int ucs4_ispunct(UCS);
+
+ #endif /* EFUNC_H */
++
+diff -rc alpine-1.10/pico/line.c alpine-1.10.fillpara/pico/line.c
+*** alpine-1.10/pico/line.c 2007-08-15 16:07:18.000000000 -0700
+--- alpine-1.10.fillpara/pico/line.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 607,620 ****
+ lisblank(LINE *line)
+ {
+ int n = 0;
+! UCS qstr[NLINE];
+
+! n = (glo_quote_str
+! && quote_match(glo_quote_str, line, qstr, NLINE))
+! ? ucs4_strlen(qstr) : 0;
+
+ for(; n < llength(line); n++)
+! if(!ucs4_isspace(lgetc(line, n).c))
+ return(FALSE);
+
+ return(TRUE);
+--- 607,618 ----
+ lisblank(LINE *line)
+ {
+ int n = 0;
+! char qstr[NLINE];
+
+! n = quote_match(default_qstr(), line, qstr, NLINE, 1);
+
+ for(; n < llength(line); n++)
+! if(!ISspace(lgetc(line, n).c))
+ return(FALSE);
+
+ return(TRUE);
+diff -rc alpine-1.10/pico/search.c alpine-1.10.fillpara/pico/search.c
+*** alpine-1.10/pico/search.c 2008-01-04 14:49:15.000000000 -0800
+--- alpine-1.10.fillpara/pico/search.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 35,41 ****
+ int readpattern(char *, int);
+ int replace_pat(UCS *, int *);
+ int replace_all(UCS *, UCS *);
+!
+
+ #define FWS_RETURN(RV) { \
+ thisflag |= CFSRCH; \
+--- 35,41 ----
+ int readpattern(char *, int);
+ int replace_pat(UCS *, int *);
+ int replace_all(UCS *, UCS *);
+! int deletepara(int, int);
+
+ #define FWS_RETURN(RV) { \
+ thisflag |= CFSRCH; \
+***************
+*** 231,236 ****
+--- 231,241 ----
+ mlerase();
+ FWS_RETURN(TRUE);
+
++ case (CTRL|'P'):
++ deletepara(0, 1);
++ mlerase();
++ FWS_RETURN(TRUE);
++
+ case (CTRL|'R'): /* toggle replacement option */
+ repl_mode = !repl_mode;
+ break;
+***************
+*** 597,603 ****
+ UCS *b;
+ UCS prompt[NPMT];
+ UCS *promptp;
+! EXTRAKEYS menu_pat[8];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+--- 602,608 ----
+ UCS *b;
+ UCS prompt[NPMT];
+ UCS *promptp;
+! EXTRAKEYS menu_pat[9];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+***************
+*** 631,636 ****
+--- 636,646 ----
+ menu_pat[i].key = (CTRL|'O');
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
++ menu_pat[++i].name = "^P";
++ menu_pat[i].label = N_("Delete Para");
++ menu_pat[i].key = (CTRL|'P');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^U";
+ /* TRANSLATORS: Instead of justifying (formatting) just a
+ single paragraph, Full Justify justifies the entire
+***************
+*** 766,772 ****
+ UCS *b;
+ UCS tpat[NPAT+20];
+ UCS *tpatp;
+! EXTRAKEYS menu_pat[7];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+--- 776,782 ----
+ UCS *b;
+ UCS tpat[NPAT+20];
+ UCS *tpatp;
+! EXTRAKEYS menu_pat[8];
+
+ menu_pat[i = 0].name = "^Y";
+ menu_pat[i].label = N_("FirstLine");
+***************
+*** 794,799 ****
+--- 804,814 ----
+ menu_pat[i].key = (CTRL|'O');
+ KS_OSDATASET(&menu_pat[i], KS_NONE);
+
++ menu_pat[++i].name = "^P";
++ menu_pat[i].label = N_("Delete Para");
++ menu_pat[i].key = (CTRL|'P');
++ KS_OSDATASET(&menu_pat[i], KS_NONE);
++
+ menu_pat[++i].name = "^U";
+ menu_pat[i].label = N_("FullJustify");
+ menu_pat[i].key = (CTRL|'U');
+***************
+*** 1032,1034 ****
+--- 1047,1071 ----
+
+ curwp->w_flag |= WFEDIT;
+ }
++
++ int
++ deletepara(int f, int n) /* Delete the current paragraph */
++ {
++ if(curbp->b_mode&MDVIEW) /* don't allow this command if */
++ return(rdonly()); /* we are in read only mode */
++
++ if(!lisblank(curwp->w_dotp))
++ gotobop(FALSE, 1);
++
++ curwp->w_markp = curwp->w_dotp;
++ curwp->w_marko = 0;
++
++ gotoeop(FALSE, 1);
++ if (curwp->w_dotp != curbp->b_linep){ /* if we are not at the end of buffer */
++ curwp->w_dotp = lforw(curwp->w_dotp); /* get one more line */
++ curwp->w_doto = 0; /* but only the beginning */
++ }
++ killregion(f,n);
++ return(TRUE);
++ }
++
+diff -rc alpine-1.10/pico/word.c alpine-1.10.fillpara/pico/word.c
+*** alpine-1.10/pico/word.c 2007-08-20 12:46:37.000000000 -0700
+--- alpine-1.10.fillpara/pico/word.c 2008-05-19 16:33:00.000000000 -0700
+***************
+*** 24,33 ****
+ */
+
+ #include "headers.h"
+!
+
+ int fpnewline(UCS *quote);
+! int fillregion(UCS *qstr, REGION *addedregion);
+ int setquotelevelinregion(int quotelevel, REGION *addedregion);
+ int is_user_separator(UCS c);
+
+--- 24,33 ----
+ */
+
+ #include "headers.h"
+! #include "../pith/osdep/color.h"
+
+ int fpnewline(UCS *quote);
+! int fillregion(UCS *qstr, UCS *istr, REGION *addedregion);
+ int setquotelevelinregion(int quotelevel, REGION *addedregion);
+ int is_user_separator(UCS c);
+
+***************
+*** 430,471 ****
+ return 0;
+ }
+
+
+ /*
+ * Return number of quotes if whatever starts the line matches the quote string
+ */
+ int
+! quote_match(UCS *q, LINE *l, UCS *buf, size_t buflen)
+ {
+! register int i, n, j, qb;
+
+! *buf = '\0';
+! if(*q == '\0')
+! return(1);
+!
+! qb = (ucs4_strlen(q) > 1 && q[ucs4_strlen(q)-1] == ' ') ? 1 : 0;
+! for(n = 0, j = 0; ;){
+! for(i = 0; j <= llength(l) && qb ? q[i+1] : q[i]; i++, j++)
+! if(q[i] != lgetc(l, j).c)
+! return(n);
+!
+! n++;
+! if((!qb && q[i] == '\0') || (qb && q[i+1] == '\0')){
+! if(ucs4_strlen(buf) + ucs4_strlen(q) + 1 < buflen){
+! ucs4_strncat(buf, q, buflen-ucs4_strlen(q)-1);
+! buf[buflen-1] = '\0';
+! if(qb && (j > llength(l) || lgetc(l, j).c != ' '))
+! buf[ucs4_strlen(buf)-1] = '\0';
+! }
+! }
+! if(j > llength(l))
+! return(n);
+! else if(qb && lgetc(l, j).c == ' ')
+! j++;
+ }
+! return(n); /* never reached */
+ }
+
+
+ /* Justify the entire buffer instead of just a paragraph */
+ int
+--- 430,600 ----
+ return 0;
+ }
+
++ /* Support of indentation of paragraphs */
++ #define is_indent_char(c) (((c) == '.' || (c) == '}' || (c) == RPAREN || \
++ (c) == '*' || (c) == '+' || is_a_digit(c) || \
++ ISspace(c) || (c) == '-' || \
++ (c) == ']') ? 1 : 0)
++ #define allowed_after_digit(c,word,k) ((((c) == '.' && \
++ allowed_after_period(next((word),(k)))) ||\
++ (c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || is_a_digit(c) || \
++ ((c) == '-' ) && \
++ allowed_after_dash(next((word),(k)))) \
++ ? 1 : 0)
++ #define allowed_after_period(c) (((c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || (c) == '-' || \
++ is_a_digit(c)) ? 1 : 0)
++ #define allowed_after_parenth(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_space(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_braces(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_star(c) ((ISspace(c) || (c) == RPAREN ||\
++ (c) == ']' || (c) == '}') ? 1 : 0)
++ #define allowed_after_dash(c) ((ISspace(c) || is_a_digit(c)) ? 1 : 0)
++ #define EOLchar(c) (((c) == '.' || (c) == ':' || (c) == '?' ||\
++ (c) == '!') ? 1 : 0)
++
++ int indent_match(char *, LINE *, char *, int, int);
++
++ /* Extended justification support */
++ #define is_cquote(c) ((c) == '>' || (c) == '|' || (c) == ']' || (c) == ':')
++ #define is_cword(c) ((((c) >= 'a') && ((c) <= 'z')) || \
++ (((c) >= 'A') && ((c) <= 'Z')) || \
++ (((c) >= '0') && ((c) <= '9')) || \
++ ((c) == ' ') || ((c) == '?') || \
++ ((c) == '@') || ((c) == '.') || \
++ ((c) == '!') || ((c) == '\'') || \
++ ((c) == ',') || ((c) == '\"') ? 1 : 0)
++ #define isaquote(c) ((c) == '\"' || (c) == '\'')
++ #define is8bit(c) ((((int) (c)) & 0x80) ? 1 : 0)
++ #define iscontrol(c) (iscntrl(((int) (c)) & 0x7f) ? 1 : 0)
++ #define forbidden(c) (((c) == '\"') || ((c) == '\'') || ((c) == '$') ||\
++ ((c) == ',') || ((c) == '.') || ((c) == '-') ||\
++ ((c) == LPAREN) || ((c) == '/')|| ((c) == '`') ||\
++ ((c) == '{') || ((c) == '\\') || (iscontrol((c))) ||\
++ (((c) >= '0') && ((c) <= '9')) || ((c) == '?'))
++ #define is_cletter(c) ((((c) >= 'a') && ((c) <= 'z'))) ||\
++ ((((c) >= 'A') && ((c) <= 'Z'))||\
++ is8bit(c))
++ #define is_cnumber(c) ((c) >= '0' && (c) <= '9')
++ #define allwd_after_word(c) (((c) == ' ') || ((c) == '>') || is_cletter(c))
++ #define allwd_after_qsword(c) (((c) != '\\') && ((c) != RPAREN))
++ #define before(word,i) (((i) > 0) ? (word)[(i) - 1] : 0)
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++ #define now(w,i) ((w)[(i)])
++ #define is_qsword(c) (((c) == ':') || ((c) == RPAREN) ? 1 : 0)
++ #define is_colon(c) (((c) == ':') ? 1 : 0)
++ #define is_rarrow(c) (((c) == '>') ? 1 : 0)
++ #define is_tilde(c) (((c) == '~') ? 1 : 0)
++ #define is_dash(c) (((c) == '-') ? 1 : 0)
++ #define is_pound(c) (((c) == '#') ? 1 : 0)
++ #define is_a_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++ #define is_allowed(c) (is_cquote(c) || is_cword(c) || is_dash(c) || \
++ is_pound(c))
++ #define qs_allowed(a) (((a)->qstype != qsGdb) && ((a)->qstype != qsProg))
++
++ /* Internal justification functions */
++ QSTRING_S *qs_quote_match(char *, LINE *, char *, int);
++ int ucs4_strlenis(UCS *);
++ void linencpy(char *, LINE *, int);
++
++
++ char *
++ default_qstr(void)
++ {
++ char *default_qs;
++ static char ucs_def[NSTRING] = {'\0'};
++
++ if(ucs_def[0] == '\0'){
++ default_qs = ucs4_to_utf8_cpystr(glo_quote_str);
++ strncpy(ucs_def, (default_qs ? default_qs : ""), NSTRING);
++ fs_give((void **)&default_qs);
++ }
++
++ return glo_quote_str ? ucs_def : "";
++ }
++
++ void
++ linencpy(word, l, buflen)
++ char word[NSTRING];
++ LINE *l;
++ int buflen;
++ {
++ int i;
++ UCS ucs_word[NSTRING];
++ char *utf_word;
++
++ word[0] = '\0';
++ if(l){
++ for (i = 0; i < buflen && i < llength(l)
++ && (ucs_word[i] = lgetc(l,i).c); i++);
++ ucs_word[i == buflen ? i-1 : i] = '\0';
++ utf_word = ucs4_to_utf8_cpystr(ucs_word);
++ strncpy(word, utf_word, (NSTRING < buflen ? NSTRING : buflen));
++ word[NSTRING-1] = '\0';
++ if(utf_word) fs_give((void **)&utf_word);
++ }
++ }
++
++ /*
++ * This function returns the quote string as a structure. In this way we
++ * have two ways to get the quote string: as a char * or as a QSTRING_S *
++ * directly.
++ */
++ QSTRING_S *
++ qs_quote_match(char *q, LINE *l, char *rqstr, int rqstrlen)
++ {
++ char GLine[NSTRING], NLine[NSTRING], PLine[NSTRING];
++ LINE *nl = l != curbp->b_linep ? lforw(l) : NULL;
++ LINE *pl = lback(l) != curbp->b_linep ? lback(l) : NULL;
++ int plb = 1;
++
++ linencpy(GLine, l, NSTRING);
++ linencpy(NLine, nl, NSTRING);
++
++ if (pl){
++ linencpy(PLine, pl, NSTRING);
++ if(lback(pl) != curbp->b_linep){
++ char PPLine[NSTRING];
++
++ linencpy(PPLine, lback(pl), NSTRING);
++ plb = line_isblank(q, PLine, GLine, PPLine, NSTRING);
++ }
++ }
++ return do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb);
++ }
+
+ /*
+ * Return number of quotes if whatever starts the line matches the quote string
++ * rqstring is pointer to raw qstring, buf points to processed qstring
+ */
+ int
+! quote_match(char *q, LINE *l, char *buf, size_t buflen, int raw)
+ {
+! QSTRING_S *qs;
+! char rqstr[NSTRING];
+
+! qs = qs_quote_match(q, l, rqstr, NSTRING);
+! flatten_qstring(qs, buf, buflen);
+! if (qs)
+! free_qs(&qs);
+!
+! if(raw){
+! strncpy(buf, rqstr, buflen < NSTRING ? buflen : NSTRING);
+! buf[buflen-1] = '\0';
+ }
+!
+! return buf && buf[0] ? strlen(buf) : 0;
+ }
+
++ int ucs4_strlenis(UCS *ucs_qstr)
++ {
++ char *str = ucs4_to_utf8_cpystr(ucs_qstr);
++ int i = (int) strlenis(str);
++
++ if(str) fs_give((void **)&str);
++ return i;
++ }
+
+ /* Justify the entire buffer instead of just a paragraph */
+ int
+***************
+*** 720,725 ****
+--- 849,855 ----
+ }
+
+ if(action == 'R' && curwp->w_markp){
++ char qstrfl[NSTRING];
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= CFFILL;
+
+***************
+*** 732,752 ****
+
+ /* determine if we're justifying quoted text or not */
+ qstr = (glo_quote_str
+! && quote_match(glo_quote_str,
+! curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp,
+! qstr2, NSTRING)
+! && *qstr2) ? qstr2 : NULL;
+!
+
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, &addedregion))
+ return(FALSE);
+
+ set_last_region_added(&addedregion);
+ }
+ else if(action == 'P'){
+
+ /*
+ * Justfiy the current paragraph.
+--- 862,886 ----
+
+ /* determine if we're justifying quoted text or not */
+ qstr = (glo_quote_str
+! && quote_match(default_qstr(),
+! (curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp),
+! qstrfl, NSTRING, 0)
+! && *qstrfl) ? utf8_to_ucs4_cpystr(qstrfl) : NULL;
+
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, NULL, &addedregion))
+ return(FALSE);
+
+ set_last_region_added(&addedregion);
++
++ if(qstr)
++ fs_give((void **)&qstr);
+ }
+ else if(action == 'P'){
++ char ind_str[NSTRING], qstrfl[NSTRING];
++ UCS *istr;
+
+ /*
+ * Justfiy the current paragraph.
+***************
+*** 758,774 ****
+ if(gotoeop(FALSE, 1) == FALSE)
+ return(FALSE);
+
+- /* determine if we're justifying quoted text or not */
+- qstr = (glo_quote_str
+- && quote_match(glo_quote_str,
+- curwp->w_dotp, qstr2, NSTRING)
+- && *qstr2) ? qstr2 : NULL;
+-
+ setmark(0,0); /* mark last line of para */
+
+ /* jump back to the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= (CFFILL | CFFLPA);
+
+--- 892,907 ----
+ if(gotoeop(FALSE, 1) == FALSE)
+ return(FALSE);
+
+ setmark(0,0); /* mark last line of para */
+
+ /* jump back to the beginning of the paragraph */
+ gotobop(FALSE, 1);
+
++ istr = indent_match(default_qstr(), curwp->w_dotp, ind_str, NSTRING, 0)
++ && *ind_str ? utf8_to_ucs4_cpystr(ind_str) : NULL;
++ qstr = (quote_match(default_qstr(), curwp->w_dotp, qstrfl, NSTRING, 0)
++ && *qstrfl) ? utf8_to_ucs4_cpystr(qstrfl) : NULL;
++
+ /* let yank() know that it may be restoring a paragraph */
+ thisflag |= (CFFILL | CFFLPA);
+
+***************
+*** 782,790 ****
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, &addedregion))
+ return(FALSE);
+
+ set_last_region_added(&addedregion);
+
+ /* Leave cursor on first char of first line after justified region */
+--- 915,929 ----
+ /*
+ * Fillregion moves dot to the end of the filled region.
+ */
+! if(!fillregion(qstr, istr, &addedregion))
+ return(FALSE);
+
++ if(qstr)
++ fs_give((void **)&qstr);
++
++ if(istr)
++ fs_give((void **)&istr);
++
+ set_last_region_added(&addedregion);
+
+ /* Leave cursor on first char of first line after justified region */
+***************
+*** 826,841 ****
+ * can delete it and restore the saved part.
+ */
+ int
+! fillregion(UCS *qstr, REGION *addedregion)
+ {
+ long c, sz, last_char = 0;
+! int i, j, qlen, same_word,
+ spaces, word_len, word_ind, line_len, ww;
+ int starts_midline = 0;
+ int ends_midline = 0;
+ int offset_into_start;
+ LINE *line_before_start, *lp;
+! UCS line_last, word[NSTRING];
+ REGION region;
+
+ /* if region starts midline insert a newline */
+--- 965,980 ----
+ * can delete it and restore the saved part.
+ */
+ int
+! fillregion(UCS *qstr, UCS *istr, REGION *addedregion)
+ {
+ long c, sz, last_char = 0;
+! int i, j, qlen, same_word, qi, pqi, qlenis,
+ spaces, word_len, word_ind, line_len, ww;
+ int starts_midline = 0;
+ int ends_midline = 0;
+ int offset_into_start;
+ LINE *line_before_start, *lp;
+! UCS line_last, word[NSTRING], quoid[NSTRING], qstr2[NSTRING];
+ REGION region;
+
+ /* if region starts midline insert a newline */
+***************
+*** 846,851 ****
+--- 985,1020 ----
+ if(curwp->w_marko > 0 && curwp->w_marko < llength(curwp->w_markp))
+ ends_midline++;
+
++ for (i = 0; (i < NSTRING) && qstr && (quoid[i] = qstr[i]); i++);
++ for (j = 0; ((i + j) < NSTRING) && istr && (quoid[i] = istr[j]); i++,j++);
++ quoid[i] = '\0';
++ qi = ucs4_strlen(quoid);
++ if (istr) /* strip trailing spaces */
++ for (;ISspace(quoid[qi - 1]); qi--);
++ quoid[qi] = '\0'; /* we have closed quoid at "X" in the first line */
++
++ if (ucs4_strlenis(quoid) > fillcol)
++ return FALSE; /* Too wide, we can't justify this! */
++
++ if (qstr && istr){
++ for (i = ucs4_strlen(qstr) - 1; ISspace(qstr[i]); i--);
++ qstr[i + 1] = '\0'; /* qstrfl */
++ }
++ qlen = ucs4_strlen(qstr); /* qstrfl*/
++ qlenis = ucs4_strlenis(qstr);
++
++ for(i = 0, qstr2[0] = '\0'; qstr && qstr[i] && (qstr2[i] = qstr[i]); i++);
++
++ if (istr && ((j = ucs4_strlenis(quoid) - ucs4_strlenis(qstr)) > 0)){
++ pqi = ucs4_strlen(qstr);
++ for (i = 0; (i < j) && (qstr2[pqi + i] = ' '); i++);
++ if (ISspace(istr[ucs4_strlen(istr) - 1]))
++ qstr2[pqi + i++] = ' ';
++ qstr2[pqi + i] = '\0';
++ /* if (!qstr)*/
++ qstr = qstr2;
++ }
++
+ /* cut the paragraph into our fill buffer */
+ fdelete();
+ if(!getregion(®ion, curwp->w_markp, curwp->w_marko))
+***************
+*** 862,886 ****
+
+ /* Now insert it back wrapped */
+ spaces = word_len = word_ind = line_len = same_word = 0;
+- qlen = qstr ? ucs4_strlen(qstr) : 0;
+
+ /* Beginning with leading quoting... */
+! if(qstr){
+ i = 0;
+! while(qstr[i]){
+! ww = wcellwidth(qstr[i]);
+ line_len += (ww >= 0 ? ww : 1);
+! linsert(1, qstr[i++]);
+ }
+
+ line_last = ' '; /* no word-flush space! */
+ }
+
+ /* remove first leading quotes if any */
+ if(starts_midline)
+ i = 0;
+ else
+! for(i = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){
+ linsert(1, line_last = (UCS) c);
+ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
+ }
+--- 1031,1055 ----
+
+ /* Now insert it back wrapped */
+ spaces = word_len = word_ind = line_len = same_word = 0;
+
+ /* Beginning with leading quoting... */
+! if(qstr || istr){
+ i = 0;
+! while(quoid[i]){
+! ww = wcellwidth(quoid[i]);
+ line_len += (ww >= 0 ? ww : 1);
+! linsert(1, quoid[i++]);
+ }
+
+ line_last = ' '; /* no word-flush space! */
++ line_len = ucs4_strlenis(quoid); /* we demand a recount! */
+ }
+
+ /* remove first leading quotes if any */
+ if(starts_midline)
+ i = 0;
+ else
+! for(i = ucs4_strlen(quoid); (c = fremove(i)) == ' ' || c == TAB; i++){
+ linsert(1, line_last = (UCS) c);
+ line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
+ }
+***************
+*** 911,925 ****
+
+ default :
+ if(spaces){ /* flush word? */
+! if((line_len - qlen > 0)
+ && line_len + word_len + 1 > fillcol
+! && ((ucs4_isspace(line_last))
+ || (linsert(1, ' ')))
+ && (line_len = fpnewline(qstr)))
+ line_last = ' '; /* no word-flush space! */
+
+ if(word_len){ /* word to write? */
+! if(line_len && !ucs4_isspace(line_last)){
+ linsert(1, ' '); /* need padding? */
+ line_len++;
+ }
+--- 1080,1094 ----
+
+ default :
+ if(spaces){ /* flush word? */
+! if((line_len - qlenis > 0)
+ && line_len + word_len + 1 > fillcol
+! && ((ISspace(line_last))
+ || (linsert(1, ' ')))
+ && (line_len = fpnewline(qstr)))
+ line_last = ' '; /* no word-flush space! */
+
+ if(word_len){ /* word to write? */
+! if(line_len && !ISspace(line_last)){
+ linsert(1, ' '); /* need padding? */
+ line_len++;
+ }
+***************
+*** 941,948 ****
+
+ if(word_ind + 1 >= NSTRING){
+ /* Magic! Fake that we output a wrapped word */
+! if((line_len - qlen > 0) && !same_word++){
+! if(!ucs4_isspace(line_last))
+ linsert(1, ' ');
+ line_len = fpnewline(qstr);
+ }
+--- 1110,1117 ----
+
+ if(word_ind + 1 >= NSTRING){
+ /* Magic! Fake that we output a wrapped word */
+! if((line_len - qlenis > 0) && !same_word++){
+! if(!ISspace(line_last))
+ linsert(1, ' ');
+ line_len = fpnewline(qstr);
+ }
+***************
+*** 964,975 ****
+ }
+
+ if(word_len){
+! if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol)){
+! if(!ucs4_isspace(line_last))
+ linsert(1, ' ');
+ (void) fpnewline(qstr);
+ }
+! else if(line_len && !ucs4_isspace(line_last))
+ linsert(1, ' ');
+
+ for(j = 0; j < word_ind; j++)
+--- 1133,1144 ----
+ }
+
+ if(word_len){
+! if((line_len - qlenis > 0) && (line_len + word_len + 1 > fillcol)){
+! if(!ISspace(line_last))
+ linsert(1, ' ');
+ (void) fpnewline(qstr);
+ }
+! else if(line_len && !ISspace(line_last))
+ linsert(1, ' ');
+
+ for(j = 0; j < word_ind; j++)
+***************
+*** 1027,1037 ****
+ int len;
+
+ lnewline();
+! for(len = 0; quote && *quote; quote++){
+ int ww;
+
+! ww = wcellwidth(*quote);
+! len += (ww >= 0 ? ww : 1);
+ linsert(1, *quote);
+ }
+
+--- 1196,1206 ----
+ int len;
+
+ lnewline();
+! for(len = ucs4_strlenis(quote); quote && *quote; quote++){
+ int ww;
+
+! /* ww = wcellwidth(*quote);
+! len += (ww >= 0 ? ww : 1);*/
+ linsert(1, *quote);
+ }
+
+***************
+*** 1175,1179 ****
+--- 1344,1388 ----
+ markregion(1);
+ }
+
++ /*
++ * This puts us at the end of the quoted region instead
++ * of on the following line. This makes it convenient
++ * for the user to follow a quotelevel adjustment with
++ * a Justify if desired.
++ */
++ if(backuptoprevline){
++ curwp->w_doto = 0;
++ backchar(0, 1);
++ }
++
++ if(ends_midline){ /* doesn't need fixing otherwise */
++ unmarkbuffer();
++ markregion(1);
++ }
++
+ return (TRUE);
+ }
++
++ /*
++ * If there is an indent string this function returns
++ * its length
++ */
++ int
++ indent_match(char *q, LINE *l, char *buf, int buflen, int raw)
++ {
++ char GLine[NSTRING];
++ int i, k, plb;
++
++ k = quote_match(q,l, buf, buflen, raw);
++ linencpy(GLine, l, NSTRING);
++ plb = (lback(l) != curbp->b_linep) ? lisblank(lback(l)) : 1;
++ if (!plb){
++ i = llength(lback(l)) - 1;
++ for (; i >= 0 && ISspace(lgetc(lback(l), i).c); i--);
++ if (EOLchar(lgetc(lback(l), i).c))
++ plb++;
++ }
++
++ return get_indent_raw_line(q, GLine, buf, buflen, k, plb);
++ }
++
+diff -rc alpine-1.10/pith/charconv/utf8.c alpine-1.10.fillpara/pith/charconv/utf8.c
+*** alpine-1.10/pith/charconv/utf8.c 2008-01-08 09:04:58.000000000 -0800
+--- alpine-1.10.fillpara/pith/charconv/utf8.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 1048,1053 ****
+--- 1048,1103 ----
+
+
+ /*
++ * Returns the screen cells width of the UTF-8 string argument, treating tabs
++ * in a special way.
++ */
++ unsigned
++ utf8_widthis(char *str)
++ {
++ unsigned width = 0;
++ int this_width;
++ UCS ucs;
++ unsigned long remaining_octets;
++ char *readptr;
++
++ if(!(str && *str))
++ return(width);
++
++ readptr = str;
++ remaining_octets = readptr ? strlen(readptr) : 0;
++
++ while(remaining_octets > 0 && *readptr){
++
++ ucs = (UCS) utf8_get((unsigned char **) &readptr, &remaining_octets);
++
++ if(ucs & U8G_ERROR){
++ /*
++ * This should not happen, but do something to handle it anyway.
++ * Treat each character as a single width character, which is what should
++ * probably happen when we actually go to write it out.
++ */
++ remaining_octets--;
++ readptr++;
++ this_width = 1;
++ }
++ else{
++ this_width = (ucs == TAB) ? ((~width & 0x07) + 1) : wcellwidth(ucs);
++
++ /*
++ * If this_width is -1 that means we can't print this character
++ * with our current locale. Writechar will print a '?'.
++ */
++ if(this_width < 0)
++ this_width = 1;
++ }
++
++ width += (unsigned) this_width;
++ }
++
++ return(width);
++ }
++
++ /*
+ * Copy UTF-8 characters from src into dst.
+ * This is intended to be used if you want to truncate a string at
+ * the start instead of the end. For example, you have a long string
+diff -rc alpine-1.10/pith/charconv/utf8.h alpine-1.10.fillpara/pith/charconv/utf8.h
+*** alpine-1.10/pith/charconv/utf8.h 2008-01-08 09:04:58.000000000 -0800
+--- alpine-1.10.fillpara/pith/charconv/utf8.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 80,85 ****
+--- 80,86 ----
+ UCS *ucs4_strchr(UCS *s, UCS c);
+ UCS *ucs4_strrchr(UCS *s, UCS c);
+ unsigned utf8_width(char *);
++ unsigned utf8_widthis(char *);
+ size_t utf8_to_width_rhs(char *, char *, size_t, unsigned);
+ int utf8_snprintf(char *, size_t, char *, ...);
+ size_t utf8_to_width(char *, char *, size_t, unsigned, unsigned *);
+diff -rc alpine-1.10/pith/color.c alpine-1.10.fillpara/pith/color.c
+*** alpine-1.10/pith/color.c 2007-08-15 13:28:09.000000000 -0700
+--- alpine-1.10.fillpara/pith/color.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 20,26 ****
+ #include "../pith/state.h"
+ #include "../pith/conf.h"
+ #include "../pith/filter.h"
+!
+
+ char *
+ color_embed(char *fg, char *bg)
+--- 20,27 ----
+ #include "../pith/state.h"
+ #include "../pith/conf.h"
+ #include "../pith/filter.h"
+! #include "../pith/mailview.h"
+! #include "../pico/estruct.h"
+
+ char *
+ color_embed(char *fg, char *bg)
+***************
+*** 69,91 ****
+ struct quote_colors *next;
+ };
+
+
+ int
+ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
+ {
+! int countem = 0;
+ struct variable *vars = ps_global->vars;
+! char *p;
+ struct quote_colors *colors = NULL, *cp, *next;
+ COLOR_PAIR *col = NULL;
+ int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
+
+ p = line;
+! if(!is_flowed)
+! while(isspace((unsigned char)*p))
+! p++;
+
+! if(p[0] == '>'){
+ struct quote_colors *c;
+
+ /*
+--- 70,179 ----
+ struct quote_colors *next;
+ };
+
++ int
++ is_word (buf, i, j)
++ char buf[NSTRING];
++ int i, j;
++ {
++ return i <= j && is_letter(buf[i]) ?
++ (i < j ? is_word(buf,i+1,j) : 1) : 0;
++ }
++
++ int
++ is_mailbox(buf,i,j)
++ char buf[NSTRING];
++ int i, j;
++ {
++ return i <= j && (is_letter(buf[i]) || is_digit(buf[i]) || buf[i] == '.')
++ ? (i < j ? is_mailbox(buf,i+1,j) : 1) : 0;
++ }
++
++ int
++ next_level_quote(buf, line, i, is_flowed)
++ char *buf;
++ char **line;
++ int i;
++ int is_flowed;
++ {
++ int j;
++
++ if (!single_level(buf[i])){
++ if(is_mailbox(buf,i,i)){
++ for (j = i; buf[j] && !isspace(buf[j]); j++);
++ if (is_word(buf,i,j-1) || is_mailbox(buf,i,j-1))
++ j += isspace(buf[j]) ? 2 : 1;
++ }
++ else{
++ switch(buf[i]){
++ case ':' :
++ if (next(buf,i) != RPAREN)
++ j = i + 1;
++ else
++ j = i + 2;
++ break;
++
++ case '-' :
++ if (next(buf,i) != '-')
++ j = i + 2;
++ else
++ j = i + 3;
++ break;
++
++ case '+' :
++ case '*' :
++ if (next(buf,i) != ' ')
++ j = i + 2;
++ else
++ j = i + 3;
++ break;
++
++ default :
++ for (j = i; buf[j] && !isspace(buf[j])
++ && (!single_level(buf[i]) && !is_letter(buf[j])); j++);
++
++ j += isspace(buf[j]) ? 1 : 0;
++ break;
++ }
++ }
++ if (line && *line)
++ (*line) += j - i;
++ }
++ else{
++ j = i+1;
++ if (line && *line)
++ (*line)++;
++ }
++ if(!is_flowed){
++ if(line && *line)
++ for(; isspace((unsigned char)*(*line)); (*line)++);
++ for (i = j; isspace((unsigned char) buf[i]); i++);
++ }
++ else i = j;
++ if (is_flowed && i != j)
++ buf[i] = '\0';
++ return i;
++ }
+
+ int
+ color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
+ {
+! int countem = 0, i, j = 0;
+ struct variable *vars = ps_global->vars;
+! char *p, buf[NSTRING] = {'\0'};
+ struct quote_colors *colors = NULL, *cp, *next;
+ COLOR_PAIR *col = NULL;
+ int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
++ int code;
++
++ code = (is_flowed ? IS_FLOWED : NO_FLOWED) | COLORAQUO;
++ select_quote(linenum, line, ins, (void *) &code);
++ strncpy(buf, tmp_20k_buf, NSTRING < SIZEOF_20KBUF ? NSTRING : SIZEOF_20KBUF);
++ buf[sizeof(buf)-1] = '\0';
+
+ p = line;
+! for(i = 0; isspace((unsigned char)buf[i]); i++, p++);
+
+! if(buf[i]){
+ struct quote_colors *c;
+
+ /*
+***************
+*** 134,140 ****
+ free_color_pair(&col);
+
+ cp = NULL;
+! while(*p == '>'){
+ cp = (cp && cp->next) ? cp->next : colors;
+
+ if(countem > 0)
+--- 222,228 ----
+ free_color_pair(&col);
+
+ cp = NULL;
+! while(buf[i]){
+ cp = (cp && cp->next) ? cp->next : colors;
+
+ if(countem > 0)
+***************
+*** 144,153 ****
+
+ countem = (countem == 1) ? 0 : countem;
+
+! p++;
+! if(!is_flowed)
+! for(; isspace((unsigned char)*p); p++)
+! ;
+ }
+
+ if(colors){
+--- 232,240 ----
+
+ countem = (countem == 1) ? 0 : countem;
+
+! i = next_level_quote(buf, &p, i, is_flowed);
+! for (; isspace((unsigned char)*p); p++);
+! for (; isspace((unsigned char)buf[i]); i++);
+ }
+
+ if(colors){
+***************
+*** 210,216 ****
+ }
+ }
+
+! return(0);
+ }
+
+
+--- 297,303 ----
+ }
+ }
+
+! return(1);
+ }
+
+
+diff -rc alpine-1.10/pith/color.h alpine-1.10.fillpara/pith/color.h
+*** alpine-1.10/pith/color.h 2007-05-08 16:38:08.000000000 -0700
+--- alpine-1.10.fillpara/pith/color.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 21,26 ****
+--- 21,44 ----
+ #include "../pith/pattern.h"
+ #include "../pith/osdep/color.h"
+
++ #define NO_FLOWED 0x0000
++ #define IS_FLOWED 0x0001
++ #define DELETEQUO 0x0010
++ #define COLORAQUO 0x0100
++ #define RAWSTRING 0x1000
++
++ /* This is needed for justification, I will move it to a better place later
++ * or maybe not
++ */
++ #define is_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++
++ #define is_letter(c) (((c) >= 'a' && (c) <= 'z') || \
++ ((c) >= 'A' && (c) <= 'Z'))
++
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++
++ #define single_level(c) (((c) == '>') || ((c) == '|') || ((c) == '~') || \
++ ((c) == ']'))
+
+ typedef struct spec_color_s {
+ int inherit; /* this isn't a color, it is INHERIT */
+***************
+*** 80,85 ****
+--- 98,104 ----
+ /* exported protoypes */
+ char *color_embed(char *, char *);
+ int colorcmp(char *, char *);
++ int next_level_quote(char *, char **, int, int);
+ int color_a_quote(long, char *, LT_INS_S **, void *);
+ void free_spec_colors(SPEC_COLOR_S **);
+
+diff -rc alpine-1.10/pith/filter.c alpine-1.10.fillpara/pith/filter.c
+*** alpine-1.10/pith/filter.c 2008-03-07 11:30:14.000000000 -0800
+--- alpine-1.10.fillpara/pith/filter.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 45,50 ****
+--- 45,51 ----
+ #include "../pith/conf.h"
+ #include "../pith/store.h"
+ #include "../pith/color.h"
++ #include "../pith/osdep/color.h"
+ #include "../pith/escapes.h"
+ #include "../pith/pipe.h"
+ #include "../pith/status.h"
+***************
+*** 8705,8710 ****
+--- 8706,8716 ----
+ margin_r,
+ indent;
+ char special[256];
++ long curlinenum; /* current line number */
++ int curqstrpos; /* current position in quote string */
++ long linenum; /* line number */
++ long qstrlen; /* multiples of 100 */
++ char **qstrln; /* qstrln[i] = quote string line i - 1 */
+ } WRAP_S;
+
+ #define WRAP_MARG_L(F) (((WRAP_S *)(F)->opt)->margin_l)
+***************
+*** 8746,8751 ****
+--- 8752,8763 ----
+ #define WRAP_COLOR(F) (((WRAP_S *)(F)->opt)->color)
+ #define WRAP_COLOR_SET(F) ((WRAP_COLOR(F)) && (WRAP_COLOR(F)->fg[0]))
+ #define WRAP_SPACES(F) (((WRAP_S *)(F)->opt)->spaces)
++ #define WRAP_CURLINE(F) (((WRAP_S *)(F)->opt)->curlinenum)
++ #define WRAP_CURPOS(F) (((WRAP_S *)(F)->opt)->curqstrpos)
++ #define WRAP_LINENUM(F) (((WRAP_S *)(F)->opt)->linenum)
++ #define WRAP_QSTRLEN(F) (((WRAP_S *)(F)->opt)->qstrlen)
++ #define WRAP_QSTRN(F) (((WRAP_S *)(F)->opt)->qstrln)
++ #define WRAP_QSTR(F, N) (((WRAP_S *)(F)->opt)->qstrln[(N)])
+ #define WRAP_PUTC(F,C,W) { \
+ if((F)->linep == WRAP_LASTC(F)){ \
+ size_t offset = (F)->linep - (F)->line; \
+***************
+*** 8823,8828 ****
+--- 8835,8842 ----
+ case CCR : /* CRLF or CR in text ? */
+ state = BOL; /* either way, handle start */
+
++ WRAP_CURLINE(f)++;
++ WRAP_CURPOS(f) = 0;
+ if(WRAP_FLOW(f)){
+ /* wrapped line? */
+ if(f->f2 == 0 && WRAP_SPC_LEN(f) && WRAP_TRL_SPC(f)){
+***************
+*** 8916,8922 ****
+
+ case BOL :
+ if(WRAP_FLOW(f)){
+! if(c == '>'){
+ WRAP_FL_QC(f) = 1; /* init it */
+ state = FL_QLEV; /* go collect it */
+ }
+--- 8930,8940 ----
+
+ case BOL :
+ if(WRAP_FLOW(f)){
+! if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && WRAP_QSTR(f, WRAP_CURLINE(f))
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)]
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)] == c){
+! WRAP_CURPOS(f)++;
+ WRAP_FL_QC(f) = 1; /* init it */
+ state = FL_QLEV; /* go collect it */
+ }
+***************
+*** 8930,8936 ****
+ }
+
+ /* quote level change implies new paragraph */
+! if(WRAP_FL_QD(f)){
+ WRAP_FL_QD(f) = 0;
+ if(WRAP_HARD(f) == 0){
+ WRAP_HARD(f) = 1;
+--- 8948,8963 ----
+ }
+
+ /* quote level change implies new paragraph */
+! if (WRAP_CURLINE(f) > 0
+! && WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && (WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL
+! || WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
+! && ((WRAP_QSTR(f, WRAP_CURLINE(f)) != NULL &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1) == NULL)
+! || (WRAP_QSTR(f, WRAP_CURLINE(f)) == NULL &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1) != NULL)
+! || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
+ WRAP_FL_QD(f) = 0;
+ if(WRAP_HARD(f) == 0){
+ WRAP_HARD(f) = 1;
+***************
+*** 8982,8989 ****
+ break;
+
+ case FL_QLEV :
+! if(c == '>'){ /* another level */
+! WRAP_FL_QC(f)++;
+ }
+ else {
+ /* if EMBEDed, process it and return here */
+--- 9009,9020 ----
+ break;
+
+ case FL_QLEV :
+! if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && WRAP_QSTR(f, WRAP_CURLINE(f))
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)]
+! && WRAP_QSTR(f, WRAP_CURLINE(f))[WRAP_CURPOS(f)] == c){
+! WRAP_CURPOS(f)++;
+! WRAP_FL_QC(f)++; /* another level */
+ }
+ else {
+ /* if EMBEDed, process it and return here */
+***************
+*** 8995,9001 ****
+ }
+
+ /* quote level change signals new paragraph */
+! if(WRAP_FL_QC(f) != WRAP_FL_QD(f)){
+ WRAP_FL_QD(f) = WRAP_FL_QC(f);
+ if(WRAP_HARD(f) == 0){ /* add hard newline */
+ WRAP_HARD(f) = 1; /* hard newline */
+--- 9026,9041 ----
+ }
+
+ /* quote level change signals new paragraph */
+! if (WRAP_CURLINE(f) > 0
+! && WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
+! && (WRAP_QSTR(f, WRAP_CURLINE(f))
+! || WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! && ((WRAP_QSTR(f, WRAP_CURLINE(f)) &&
+! !WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! || (!WRAP_QSTR(f, WRAP_CURLINE(f)) &&
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1))
+! || strcmp(WRAP_QSTR(f, WRAP_CURLINE(f)),
+! WRAP_QSTR(f, WRAP_CURLINE(f) - 1)))){
+ WRAP_FL_QD(f) = WRAP_FL_QC(f);
+ if(WRAP_HARD(f) == 0){ /* add hard newline */
+ WRAP_HARD(f) = 1; /* hard newline */
+***************
+*** 9052,9057 ****
+--- 9092,9104 ----
+ state = FL_SIG;
+ break;
+
++ case ' ' : /* what? */
++ if (WRAP_CURLINE(f) < WRAP_QSTRLEN(f)
++ && WRAP_QSTR(f, WRAP_CURLINE(f))){
++ WRAP_SPC_LEN(f)++;
++ so_writec(' ', WRAP_SPACES(f));
++ }
++
+ default : /* something else */
+ state = DFL;
+ goto case_dfl; /* handle c like DFL */
+***************
+*** 9068,9074 ****
+ &eob); /* note any embedded*/
+ wrap_eol(f, 1, &ip, &eib,
+ &op, &eob); /* plunk down newline */
+! wrap_bol(f, 1, 1, &ip, &eib,
+ &op, &eob); /* write any prefix */
+ }
+
+--- 9115,9121 ----
+ &eob); /* note any embedded*/
+ wrap_eol(f, 1, &ip, &eib,
+ &op, &eob); /* plunk down newline */
+! wrap_bol(f, 1, WRAP_FLOW(f), &ip, &eib,
+ &op, &eob); /* write any prefix */
+ }
+
+***************
+*** 9565,9571 ****
+ wrap_flush_embed(f, &ip, &eib, &op, &eob);
+ wrap_eol(f, 1, &ip, &eib, &op,
+ &eob); /* plunk down newline */
+! wrap_bol(f,1,1, &ip, &eib, &op,
+ &eob); /* write any prefix */
+ }
+
+--- 9612,9618 ----
+ wrap_flush_embed(f, &ip, &eib, &op, &eob);
+ wrap_eol(f, 1, &ip, &eib, &op,
+ &eob); /* plunk down newline */
+! wrap_bol(f,1,WRAP_FLOW(f), &ip, &eib, &op,
+ &eob); /* write any prefix */
+ }
+
+***************
+*** 9638,9643 ****
+--- 9685,9697 ----
+ if(WRAP_COLOR(f))
+ free_color_pair(&WRAP_COLOR(f));
+
++ { long i;
++ for (i = 0L; i < WRAP_QSTRLEN(f); i++)
++ if (WRAP_QSTR(f,i))
++ fs_give((void **) &(WRAP_QSTR(f,i)));
++ fs_give((void **)&WRAP_QSTRN(f));
++ }
++
+ fs_give((void **) &f->line); /* free temp line buffer */
+ so_give(&WRAP_SPACES(f));
+ fs_give((void **) &f->opt); /* free wrap widths struct */
+***************
+*** 9988,9994 ****
+ {
+ int j, i;
+ COLOR_PAIR *col = NULL;
+! char *prefix = NULL, *last_prefix = NULL;
+
+ if(ps_global->VAR_QUOTE_REPLACE_STRING){
+ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
+--- 10042,10049 ----
+ {
+ int j, i;
+ COLOR_PAIR *col = NULL;
+! char *prefix = NULL, *last_prefix = NULL, *wrap_qstr = NULL;
+! int level = 0, oldj, len;
+
+ if(ps_global->VAR_QUOTE_REPLACE_STRING){
+ get_pair(ps_global->VAR_QUOTE_REPLACE_STRING, &prefix, &last_prefix, 0, 0);
+***************
+*** 9997,10006 ****
+ last_prefix = NULL;
+ }
+ }
+!
+! for(j = 0; j < WRAP_FL_QD(f); j++){
+ if(WRAP_USE_CLR(f)){
+! if((j % 3) == 0
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
+--- 10052,10073 ----
+ last_prefix = NULL;
+ }
+ }
+!
+! if(WRAP_CURLINE(f) < WRAP_QSTRLEN(f) && WRAP_QSTR(f, WRAP_CURLINE(f)))
+! wrap_qstr = cpystr(WRAP_QSTR(f, WRAP_CURLINE(f)));
+! len = wrap_qstr ? strlen(wrap_qstr) : 0;
+!
+! for (j = wrap_qstr && *wrap_qstr == ' ' ? 1 : 0;
+! j < len && isspace((unsigned char)wrap_qstr[j]); j++){
+! GF_PUTC_GLO(f->next, wrap_qstr[j]);
+! f->n += ((wrap_qstr[j] == TAB) ? (~f->n & 0x07) + 1 : 1);
+! }
+!
+! for(; j < len && level < len; level++){
+! oldj = j;
+! j = next_level_quote(wrap_qstr, (char **)NULL, j, WRAP_FLOW(f));
+ if(WRAP_USE_CLR(f)){
+! if((level % 3) == 0
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE1_FORE_COLOR,
+***************
+*** 10008,10014 ****
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((j % 3) == 1
+ && ps_global->VAR_QUOTE2_FORE_COLOR
+ && ps_global->VAR_QUOTE2_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
+--- 10075,10081 ----
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((level % 3) == 1
+ && ps_global->VAR_QUOTE2_FORE_COLOR
+ && ps_global->VAR_QUOTE2_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE2_FORE_COLOR,
+***************
+*** 10016,10022 ****
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((j % 3) == 2
+ && ps_global->VAR_QUOTE3_FORE_COLOR
+ && ps_global->VAR_QUOTE3_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
+--- 10083,10089 ----
+ && pico_is_good_colorpair(col)){
+ GF_COLOR_PUTC(f, col);
+ }
+! else if((level % 3) == 2
+ && ps_global->VAR_QUOTE3_FORE_COLOR
+ && ps_global->VAR_QUOTE3_BACK_COLOR
+ && (col = new_color_pair(ps_global->VAR_QUOTE3_FORE_COLOR,
+***************
+*** 10030,10072 ****
+ }
+ }
+
+ if(!WRAP_LV_FLD(f)){
+ if(!WRAP_FOR_CMPS(f) && ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
+ for(i = 0; prefix[i]; i++)
+ GF_PUTC_GLO(f->next, prefix[i]);
+! f->n += utf8_width(prefix);
+! }
+! else if(ps_global->VAR_REPLY_STRING
+! && (!strcmp(ps_global->VAR_REPLY_STRING, ">")
+! || !strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
+! GF_PUTC_GLO(f->next, '>');
+! f->n += 1;
+ }
+ else{
+! GF_PUTC_GLO(f->next, '>');
+! GF_PUTC_GLO(f->next, ' ');
+! f->n += 2;
+ }
+ }
+ else{
+! GF_PUTC_GLO(f->next, '>');
+! f->n += 1;
+ }
+ }
+ if(j && WRAP_LV_FLD(f)){
+ GF_PUTC_GLO(f->next, ' ');
+ f->n++;
+ }
+! else if(j && last_prefix){
+ for(i = 0; last_prefix[i]; i++)
+ GF_PUTC_GLO(f->next, last_prefix[i]);
+! f->n += utf8_width(last_prefix);
+ }
+
+ if(prefix)
+ fs_give((void **)&prefix);
+ if(last_prefix)
+ fs_give((void **)&last_prefix);
+
+ return 0;
+ }
+--- 10097,10156 ----
+ }
+ }
+
++ if (j > 1 && wrap_qstr[j-1] == ' ')
++ j -= 1;
++
+ if(!WRAP_LV_FLD(f)){
+ if(!WRAP_FOR_CMPS(f) && ps_global->VAR_QUOTE_REPLACE_STRING && prefix){
+ for(i = 0; prefix[i]; i++)
+ GF_PUTC_GLO(f->next, prefix[i]);
+! f->n += utf8_widthis(prefix);
+ }
+ else{
+! for (i = oldj; i < j; i++)
+! GF_PUTC_GLO(f->next, wrap_qstr[i]);
+! f->n += j - oldj;
+ }
+ }
+ else{
+! for (i = oldj; i < j; i++)
+! GF_PUTC_GLO(f->next, wrap_qstr[i]);
+! f->n += j - oldj;
+! }
+! for (i = j; isspace((unsigned char)wrap_qstr[i]); i++);
+! if(!wrap_qstr[i]){
+! f->n += i - j;
+! for (; j < i; j++)
+! GF_PUTC_GLO(f->next, ' ');
+! }
+! else{
+! if((WRAP_LV_FLD(f)
+! || !ps_global->VAR_QUOTE_REPLACE_STRING || !prefix)
+! || !ps_global->VAR_REPLY_STRING
+! || (strcmp(ps_global->VAR_REPLY_STRING, ">")
+! && strcmp(ps_global->VAR_REPLY_STRING, "\">\""))){
+! GF_PUTC_GLO(f->next, ' ');
+! f->n += 1;
+! }
+ }
++ for (; isspace((unsigned char)wrap_qstr[j]); j++);
+ }
+ if(j && WRAP_LV_FLD(f)){
+ GF_PUTC_GLO(f->next, ' ');
+ f->n++;
+ }
+! else if(j && !value_is_space(wrap_qstr) && last_prefix){
+ for(i = 0; last_prefix[i]; i++)
+ GF_PUTC_GLO(f->next, last_prefix[i]);
+! f->n += utf8_widthis(last_prefix);
+ }
+
+ if(prefix)
+ fs_give((void **)&prefix);
+ if(last_prefix)
+ fs_give((void **)&last_prefix);
++ if (wrap_qstr)
++ fs_give((void **)&wrap_qstr);
+
+ return 0;
+ }
+***************
+*** 10098,10103 ****
+--- 10182,10193 ----
+ wrap->hdr_color = (GFW_HDRCOLOR & flags) == GFW_HDRCOLOR;
+ wrap->for_compose = (GFW_FORCOMPOSE & flags) == GFW_FORCOMPOSE;
+ wrap->handle_soft_hyphen = (GFW_SOFTHYPHEN & flags) == GFW_SOFTHYPHEN;
++ wrap->curlinenum = 0L;
++ wrap->curqstrpos = 0;
++ wrap->linenum = 0L;
++ wrap->qstrlen = 100L;
++ wrap->qstrln = (char **) fs_get(100*sizeof(char *));
++ memset(wrap->qstrln, 0, 100*sizeof(char *));
+
+ return((void *) wrap);
+ }
+***************
+*** 10541,10547 ****
+--- 10631,10839 ----
+ } \
+ }
+
++ #define ADD_QUOTE_STRING(F) { \
++ int len = tmp_20k_buf[0] ? strlen(tmp_20k_buf) + 1 : 0; \
++ FILTER_S *fltr; \
++ \
++ for(fltr = (F); fltr && fltr->f != gf_wrap; fltr = fltr->next); \
++ if (fltr){ \
++ if (WRAP_LINENUM(fltr) >= WRAP_QSTRLEN(fltr)){ \
++ fs_resize((void **)&WRAP_QSTRN(fltr), \
++ (WRAP_QSTRLEN(fltr) + 100) * sizeof(char *)); \
++ memset(WRAP_QSTRN(fltr)+WRAP_QSTRLEN(fltr), 0, \
++ 100*sizeof(char*)); \
++ WRAP_QSTRLEN(fltr) += 100L; \
++ } \
++ if (len){ \
++ WRAP_QSTR(fltr, WRAP_LINENUM(fltr)) = \
++ (char *) fs_get(len*sizeof(char)); \
++ WRAP_QSTR(fltr, WRAP_LINENUM(fltr)) = cpystr(tmp_20k_buf);\
++ } \
++ WRAP_LINENUM(fltr)++; \
++ } \
++ }
++
++ /* This macro is used in gf_quote_test. It receives a return code
++ from a filter. All filters that will print something must send
++ return code 0, except color_a_quote which must send return code
++ 1
++ */
++
++ #define GF_ADD_QUOTED_LINE(F, line) \
++ { \
++ LT_INS_S *ins = NULL, *insp; \
++ int done; \
++ char *gline, *cline;\
++ unsigned char ch;\
++ register char *cp;\
++ register int l;\
++ \
++ for (gline = cline = line; gline && cline; ){\
++ if(cline = strchr(gline,'\012'))\
++ *cline = '\0';\
++ done = (*((LINETEST_S *) (F)->opt)->f)((F)->n++, gline, &ins,\
++ ((LINETEST_S *) (F)->opt)->local);\
++ if (done < 2){ \
++ if(done == 1)\
++ ADD_QUOTE_STRING((F));\
++ for(insp = ins, cp = gline; *cp ; ){\
++ if(insp && cp == insp->where){\
++ if(insp->len > 0){ \
++ for(l = 0; l < insp->len; l++){\
++ ch = (unsigned char) insp->text[l];\
++ GF_PUTC((F)->next, ch);\
++ }\
++ insp = insp->next;\
++ continue; \
++ } else if(insp->len < 0){ \
++ cp -= insp->len; \
++ insp = insp->next; \
++ continue; \
++ } \
++ }\
++ GF_PUTC((F)->next, *cp);\
++ cp++;\
++ }\
++ while(insp){\
++ for(l = 0; l < insp->len; l++){\
++ ch = (unsigned char) insp->text[l];\
++ GF_PUTC((F)->next, ch);\
++ }\
++ insp = insp->next;\
++ }\
++ gf_line_test_free_ins(&ins);\
++ if(cline){ \
++ *cline = '\012';\
++ gline += cline - gline + 1;\
++ }\
++ GF_PUTC((F)->next, '\015');\
++ GF_PUTC((F)->next, '\012');\
++ }\
++ }\
++ }
++ /* test second line of old line first */
++ #define SECOND_LINE_QUOTE_TEST(line, F) \
++ {\
++ *p = '\0';\
++ for (i = 0; ((F)->oldline)[i] && ((F)->oldline)[i] != '\015'; i++); \
++ if (((F)->oldline)[i]){\
++ i += (((F)->oldline)[i+1] == '\012') ? 2 : 1;\
++ line = (F)->oldline + i;\
++ }\
++ for (i = 0; ((F)->line) \
++ && (i < LINE_TEST_BLOCK) \
++ && (i < SIZEOF_20KBUF)\
++ && ((F)->line)[i] \
++ && (((F)->line)[i] != '\015')\
++ && (((F)->line)[i] != '\012')\
++ && (tmp_20k_buf[i] = ((F)->line)[i]); i++);\
++ tmp_20k_buf[i] = '\0';\
++ GF_ADD_QUOTED_LINE((F), line);\
++ }
++
++ #define FIRST_LINE_QUOTE_TEST(line, F)\
++ {\
++ *p = '\0';\
++ line = (F)->line;\
++ if ((F)->oldline)\
++ fs_give((void **)&(F)->oldline);\
++ (F)->oldline = cpystr(line);\
++ for (i = 0; line[i] && line[i] != '\015' && line[i] != '\012'; i++); \
++ if ((line[i] == '\012') && ((i == 0) || ((i > 0) && line[i-1] != '\015'))){\
++ i++;\
++ for (; line[i] && line[i] != '\015' && line[i] != '\012'; i++); \
++ }\
++ if (line[i]){\
++ (line[i]) = '\0';\
++ i+= (line[i+1] == '\012') ? 2 : 1;\
++ }\
++ for (j = 0; ((F)->line) \
++ && ((i + j) < LINE_TEST_BLOCK) \
++ && (j < SIZEOF_20KBUF) \
++ && ((F)->line)[i + j] \
++ && (((F)->line)[i + j] != '\015')\
++ && (((F)->line)[i + j] != '\012')\
++ && (tmp_20k_buf[j] = ((F)->line)[i + j]); j++);\
++ tmp_20k_buf[j] = '\0';\
++ GF_ADD_QUOTED_LINE((F), line);\
++ }
++
++
++ void
++ gf_quote_test(f, flg)
++ FILTER_S *f;
++ int flg;
++ {
++ register char *p = f->linep;
++ register char *eobuf = GF_LINE_TEST_EOB(f);
++ char *line = NULL;
++ int i, j;
++ GF_INIT(f, f->next);
++
++ if(flg == GF_DATA){
++ register unsigned char c;
++ register int state = f->f1;
++
++ while(GF_GETC(f, c)){
++
++ if(state == 2){ /* two full lines read */
++ state = 0;
++
++ /* first process the second line of an old line */
++ if (f->oldline && f->oldline[0])
++ SECOND_LINE_QUOTE_TEST(line, f);
++
++ /* now we process the first line */
++ FIRST_LINE_QUOTE_TEST(line, f);
++
++ p = f->line;
++ continue;
++ }
++ if(c == '\015'){
++ state++;
++ if (state == 1)
++ GF_LINE_TEST_ADD(f, c);
++ }
++ else
++ GF_LINE_TEST_ADD(f, c);
++ }
++
++ f->f1 = state;
++ GF_END(f, f->next);
++ }
++ else if(flg == GF_EOD){
++ /* first process the second line of an old line */
++ if (f->oldline && f->oldline[0])
++ SECOND_LINE_QUOTE_TEST(line, f);
++
++ /* now we process the first line */
++ FIRST_LINE_QUOTE_TEST(line, f);
++
++ /* We are out of data. In this case we have processed the second
++ * line of an oldline, then the first line of a line, but we need
++ * to process the second line of the given line. We do this by
++ * processing it now!.
++ */
++ if (line[i]){
++ tmp_20k_buf[0] = '\0'; /* No next line */
++ GF_ADD_QUOTED_LINE(f, line+i);
++ }
+
++ fs_give((void **) &f->oldline); /* free old line buffer */
++ fs_give((void **) &f->line); /* free line buffer */
++ fs_give((void **) &f->opt); /* free test struct */
++ GF_FLUSH(f->next);
++ (*f->next->f)(f->next, GF_EOD);
++ }
++ else if(flg == GF_RESET){
++ f->f1 = 0; /* state */
++ f->n = 0L; /* line number */
++ f->f2 = LINE_TEST_BLOCK; /* size of alloc'd line */
++ f->line = p = (char *) fs_get(f->f2 * sizeof(char));
++ }
++
++ f->linep = p;
++ }
+
+ /*
+ * this simple filter accumulates characters until a newline, offers it
+diff -rc alpine-1.10/pith/filter.h alpine-1.10.fillpara/pith/filter.h
+*** alpine-1.10/pith/filter.h 2008-03-05 10:56:28.000000000 -0800
+--- alpine-1.10.fillpara/pith/filter.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 194,199 ****
+--- 194,200 ----
+ void *gf_prepend_editorial_opt(prepedtest_t, char *);
+ void gf_nvtnl_local(FILTER_S *, int);
+ void gf_local_nvtnl(FILTER_S *, int);
++ void gf_quote_test(FILTER_S *, int);
+ void *gf_url_hilite_opt(URL_HILITE_S *, HANDLE_S **, int);
+
+
+diff -rc alpine-1.10/pith/filttype.h alpine-1.10.fillpara/pith/filttype.h
+*** alpine-1.10/pith/filttype.h 2007-04-25 21:06:02.000000000 -0700
+--- alpine-1.10.fillpara/pith/filttype.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 35,40 ****
+--- 35,42 ----
+ unsigned char t; /* temporary char */
+ char *line; /* place for temporary storage */
+ char *linep; /* pointer into storage space */
++ char *oldline; /* the previous line to "line" */
++ char *oldlinep; /* the previous line to "line" */
+ void *opt; /* optional per instance data */
+ void *data; /* misc internal data pointer */
+ unsigned char queue[1 + GF_MAXBUF];
+diff -rc alpine-1.10/pith/mailview.c alpine-1.10.fillpara/pith/mailview.c
+*** alpine-1.10/pith/mailview.c 2008-03-05 10:56:28.000000000 -0800
+--- alpine-1.10.fillpara/pith/mailview.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 50,56 ****
+ #include "../pith/ablookup.h"
+ #include "../pith/escapes.h"
+ #include "../pith/keyword.h"
+!
+
+ #define FBUF_LEN (50)
+
+--- 50,59 ----
+ #include "../pith/ablookup.h"
+ #include "../pith/escapes.h"
+ #include "../pith/keyword.h"
+! #include "../pith/osdep/color.h"
+! #include "../pico/estruct.h"
+! #include "../pico/pico.h"
+! #include "../pico/efunc.h"
+
+ #define FBUF_LEN (50)
+
+***************
+*** 282,288 ****
+ && pico_usingcolor()
+ && ps_global->VAR_SIGNATURE_FORE_COLOR
+ && ps_global->VAR_SIGNATURE_BACK_COLOR){
+! gf_link_filter(gf_line_test, gf_line_test_opt(color_signature, &is_in_sig));
+ }
+
+ if((flgs & FM_DISPLAY)
+--- 285,291 ----
+ && pico_usingcolor()
+ && ps_global->VAR_SIGNATURE_FORE_COLOR
+ && ps_global->VAR_SIGNATURE_BACK_COLOR){
+! gf_link_filter(gf_quote_test, gf_line_test_opt(color_signature, &is_in_sig));
+ }
+
+ if((flgs & FM_DISPLAY)
+***************
+*** 290,297 ****
+ && pico_usingcolor()
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR){
+! gf_link_filter(gf_line_test, gf_line_test_opt(color_a_quote, NULL));
+ }
+
+ if(!(flgs & FM_NOWRAP)){
+ wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
+--- 293,302 ----
+ && pico_usingcolor()
+ && ps_global->VAR_QUOTE1_FORE_COLOR
+ && ps_global->VAR_QUOTE1_BACK_COLOR){
+! gf_link_filter(gf_quote_test, gf_line_test_opt(color_a_quote, NULL));
+ }
++ else
++ gf_link_filter(gf_quote_test,gf_line_test_opt(select_quote, NULL));
+
+ if(!(flgs & FM_NOWRAP)){
+ wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
+***************
+*** 1071,1097 ****
+ color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig)
+ {
+ struct variable *vars = ps_global->vars;
+! int *in_sig_block;
+ COLOR_PAIR *col = NULL;
+
+ if(is_in_sig == NULL)
+ return 0;
+
+ in_sig_block = (int *) is_in_sig;
+
+! if(!strcmp(line, SIGDASHES))
+! *in_sig_block = START_SIG_BLOCK;
+! else if(*line == '\0')
+ /*
+ * Suggested by Eduardo: allow for a blank line right after
+ * the sigdashes.
+ */
+ *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+ else
+ *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+
+ if(*in_sig_block != OUT_SIG_BLOCK
+ && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
+ && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
+--- 1076,1164 ----
+ color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig)
+ {
+ struct variable *vars = ps_global->vars;
+! int *in_sig_block, i, j,same_qstr = 0, plb;
+ COLOR_PAIR *col = NULL;
++ static char GLine[NSTRING] = {'\0'};
++ static char PLine[NSTRING] = {'\0'};
++ static char PPLine[NSTRING] = {'\0'};
++ char NLine[NSTRING] = {'\0'};
++ char rqstr[NSTRING] = {'\0'};
++ char *p;
++ static char *buf, buf2[NSTRING] = {'\0'};
++ QSTRING_S *qs;
++ static int qstrlen = 0;
+
+ if(is_in_sig == NULL)
+ return 0;
+
++ if (linenum > 0){
++ strncpy(PLine, GLine, sizeof(PLine));
++ PLine[sizeof(PLine)-1] = '\0';
++ }
++
++ if(p = strchr(tmp_20k_buf, '\015')) *p = '\0';
++ strncpy(NLine, tmp_20k_buf, sizeof(NLine));
++ NLine[sizeof(NLine) - 1] = '\0';
++ if (p) *p = '\015';
++
++ strncpy(GLine, line, sizeof(GLine));
++ GLine[sizeof(GLine) - 1] = '\0';
++
++ plb = line_isblank((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"), PLine, GLine, PPLine, NSTRING);
++ qs = do_quote_match((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"),
++ GLine, NLine, PLine, rqstr, NSTRING, plb);
++ if(linenum > 0)
++ strncpy(PPLine, PLine, NSTRING);
++ strncpy(buf2, rqstr, NSTRING);
++ i = buf2 && buf2[0] ? strlen(buf2) : 0;
++ free_qs(&qs);
++
++ /* determine if buf and buf2 are the same quote string */
++ if (!struncmp(buf, buf2, qstrlen)){
++ for (j = qstrlen; buf2[j] && isspace((unsigned char)buf2[j]); j++);
++ if (!buf2[j] || buf2[j] == '|' || (buf2[j] == '*' && buf2[j+1] != '>'))
++ same_qstr++;
++ }
++
+ in_sig_block = (int *) is_in_sig;
+
+! if (*in_sig_block != OUT_SIG_BLOCK){
+! if (line && *line && (strlen(line) >= qstrlen) && same_qstr)
+! line += qstrlen;
+! else if (strlen(line) < qstrlen)
+! line += i;
+! else if (!same_qstr)
+! *in_sig_block = OUT_SIG_BLOCK;
+! }
+! else
+! line += i;
+!
+! if(!strcmp(line, SIGDASHES) || !strcmp(line, "--")){
+! *in_sig_block = START_SIG_BLOCK;
+! buf = (char *) fs_get((i + 1)*sizeof(char));
+! buf = cpystr(buf2);
+! qstrlen = i;
+! }
+! else if(*line == '\0'){
+ /*
+ * Suggested by Eduardo: allow for a blank line right after
+ * the sigdashes.
+ */
+ *in_sig_block = (*in_sig_block == START_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
++ }
+ else
+ *in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
+ ? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+
++ if (*in_sig_block == OUT_SIG_BLOCK){
++ qstrlen = 0; /* reset back in case there's another paragraph */
++ if (buf)
++ fs_give((void **)&buf);
++ }
++
+ if(*in_sig_block != OUT_SIG_BLOCK
+ && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
+ && (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
+***************
+*** 1651,1656 ****
+--- 1718,1794 ----
+ }
+
+
++ /* This filter gives a quote string of a line. It sends its reply back to the
++ calling filter in the tmp_20k_buf variable. This filter replies with
++ the full quote string including tailing spaces if any. It is the
++ responsibility of the calling filter to figure out if thos spaces are
++ useful for that filter or if they should be removed before doing any
++ useful work. For example, color_a_quote does not require the trailing
++ spaces, but gf_wrap does.
++ */
++ int
++ select_quote(long linenum, char *line, LT_INS_S **ins, void *local)
++ {
++ int i, plb, *code;
++ char rqstr[NSTRING] = {'\0'}, buf[NSTRING] = {'\0'};
++ char GLine[NSTRING] = {'\0'}, PLine[NSTRING] = {'\0'};
++ char PPLine[NSTRING] = {'\0'}, NLine[NSTRING] = {'\0'};
++ static char GLine1[NSTRING] = {'\0'};
++ static char PLine1[NSTRING] = {'\0'};
++ static char PPLine1[NSTRING] = {'\0'};
++ static char GLine2[NSTRING] = {'\0'};
++ static char PLine2[NSTRING] = {'\0'};
++ static char PPLine2[NSTRING] = {'\0'};
++ QSTRING_S *qs;
++ int buflen = NSTRING < SIZEOF_20KBUF ? NSTRING - 1: SIZEOF_20KBUF - 1;
++ int who, raw;
++
++ code = (int *)local;
++ who = code ? (*code & COLORAQUO) : 0; /* may I ask who is calling? */
++ raw = code ? (*code & RAWSTRING) : 0; /* return raw string */
++ strncpy(GLine, (who ? GLine1 : GLine2), buflen);
++ strncpy(PLine, (who ? PLine1 : PLine2), buflen);
++ strncpy(PPLine, (who ? PPLine1 : PPLine2), buflen);
++
++ if (linenum > 0)
++ strncpy(PLine, GLine, buflen);
++
++ strncpy(NLine, tmp_20k_buf, buflen);
++
++ if (line)
++ strncpy(GLine, line, buflen);
++ else
++ GLine[0] = '\0';
++
++
++ plb = line_isblank((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"), PLine, GLine, PPLine, NSTRING);
++
++ qs = do_quote_match((ps_global->prefix && *ps_global->prefix
++ ? ps_global->prefix : ">"), GLine, NLine, PLine,
++ rqstr, NSTRING, plb);
++ if (raw)
++ strncpy(buf, rqstr, NSTRING);
++ else
++ flatten_qstring(qs, buf, NSTRING);
++ free_qs(&qs);
++
++ /* do not paint an extra level for a line with a >From string at the
++ * begining of it
++ */
++ if (buf[0]){
++ i = strlen(buf);
++ if (strlen(line) >= i + 6 && !strncmp(line+i-1,">From ", 6))
++ buf[i - 1] = '\0';
++ }
++ strncpy(tmp_20k_buf, buf, buflen);
++ if (linenum > 0)
++ strncpy((who ? PPLine1 : PPLine2), PLine, buflen);
++ strncpy((who ? GLine1 : GLine2), GLine, buflen);
++ strncpy((who ? PLine1 : PLine2), PLine, buflen);
++ return 1;
++ }
++
+
+ #define UES_LEN 12
+ #define UES_MAX 32
+diff -rc alpine-1.10/pith/mailview.h alpine-1.10.fillpara/pith/mailview.h
+*** alpine-1.10/pith/mailview.h 2008-03-05 10:56:28.000000000 -0800
+--- alpine-1.10.fillpara/pith/mailview.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 141,146 ****
+--- 141,147 ----
+ char *display_parameters(PARAMETER *);
+ char *pine_fetch_header(MAILSTREAM *, long, char *, char **, long);
+ int color_signature(long, char *, LT_INS_S **, void *);
++ int select_quote(long, char *, LT_INS_S **, void *);
+ int scroll_handle_start_color(char *, size_t, int *);
+ int scroll_handle_end_color(char *, size_t, int *, int);
+ int width_at_this_position(unsigned char *, unsigned long);
+diff -rc alpine-1.10/pith/osdep/color.c alpine-1.10.fillpara/pith/osdep/color.c
+*** alpine-1.10/pith/osdep/color.c 2006-09-26 12:30:49.000000000 -0700
+--- alpine-1.10.fillpara/pith/osdep/color.c 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 31,37 ****
+
+ #include <system.h>
+ #include "./color.h"
+!
+
+
+ /*
+--- 31,37 ----
+
+ #include <system.h>
+ #include "./color.h"
+! #include "./collate.h"
+
+
+ /*
+***************
+*** 91,93 ****
+--- 91,1268 ----
+ {
+ return(pico_set_colors(col ? col->fg : NULL, col ? col->bg : NULL, flags));
+ }
++
++
++ /*
++ * Extended Justification support also does not belong here
++ * but otherwise webpine will not build, so we move everything
++ * here. Hopefully this will be the permanent place for these
++ * routines. This routines used to be in pico/word.c
++ */
++ #define NSTRING 256
++ #include "../../include/general.h"
++
++ /* Support of indentation of paragraphs */
++ #define is_indent_char(c) (((c) == '.' || (c) == '}' || (c) == RPAREN || \
++ (c) == '*' || (c) == '+' || is_a_digit(c) || \
++ ISspace(c) || (c) == '-' || \
++ (c) == ']') ? 1 : 0)
++ #define allowed_after_digit(c,word,k) ((((c) == '.' && \
++ allowed_after_period(next((word),(k)))) ||\
++ (c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || is_a_digit(c) || \
++ ((c) == '-' ) && \
++ allowed_after_dash(next((word),(k)))) \
++ ? 1 : 0)
++ #define allowed_after_period(c) (((c) == RPAREN || (c) == '}' || (c) == ']' ||\
++ ISspace(c) || (c) == '-' || \
++ is_a_digit(c)) ? 1 : 0)
++ #define allowed_after_parenth(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_space(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_braces(c) (ISspace(c) ? 1 : 0)
++ #define allowed_after_star(c) ((ISspace(c) || (c) == RPAREN ||\
++ (c) == ']' || (c) == '}') ? 1 : 0)
++ #define allowed_after_dash(c) ((ISspace(c) || is_a_digit(c)) ? 1 : 0)
++ #define EOLchar(c) (((c) == '.' || (c) == ':' || (c) == '?' ||\
++ (c) == '!') ? 1 : 0)
++
++
++ /* Extended justification support */
++ #define is_cquote(c) ((c) == '>' || (c) == '|' || (c) == ']' || (c) == ':')
++ #define is_cword(c) ((((c) >= 'a') && ((c) <= 'z')) || \
++ (((c) >= 'A') && ((c) <= 'Z')) || \
++ (((c) >= '0') && ((c) <= '9')) || \
++ ((c) == ' ') || ((c) == '?') || \
++ ((c) == '@') || ((c) == '.') || \
++ ((c) == '!') || ((c) == '\'') || \
++ ((c) == ',') || ((c) == '\"') ? 1 : 0)
++ #define isaquote(c) ((c) == '\"' || (c) == '\'')
++ #define is8bit(c) ((((int) (c)) & 0x80) ? 1 : 0)
++ #define iscontrol(c) (iscntrl(((int) (c)) & 0x7f) ? 1 : 0)
++ #define forbidden(c) (((c) == '\"') || ((c) == '\'') || ((c) == '$') ||\
++ ((c) == ',') || ((c) == '.') || ((c) == '-') ||\
++ ((c) == LPAREN) || ((c) == '/')|| ((c) == '`') ||\
++ ((c) == '{') || ((c) == '\\') || (iscontrol((c))) ||\
++ (((c) >= '0') && ((c) <= '9')) || ((c) == '?'))
++ #define is_cletter(c) ((((c) >= 'a') && ((c) <= 'z'))) ||\
++ ((((c) >= 'A') && ((c) <= 'Z'))||\
++ is8bit(c))
++ #define is_cnumber(c) ((c) >= '0' && (c) <= '9')
++ #define allwd_after_word(c) (((c) == ' ') || ((c) == '>') || is_cletter(c))
++ #define allwd_after_qsword(c) (((c) != '\\') && ((c) != RPAREN))
++ #define before(word,i) (((i) > 0) ? (word)[(i) - 1] : 0)
++ #define next(w,i) ((((w)[(i)]) != 0) ? ((w)[(i) + 1]) : 0)
++ #define now(w,i) ((w)[(i)])
++ #define is_qsword(c) (((c) == ':') || ((c) == RPAREN) ? 1 : 0)
++ #define is_colon(c) (((c) == ':') ? 1 : 0)
++ #define is_rarrow(c) (((c) == '>') ? 1 : 0)
++ #define is_tilde(c) (((c) == '~') ? 1 : 0)
++ #define is_dash(c) (((c) == '-') ? 1 : 0)
++ #define is_pound(c) (((c) == '#') ? 1 : 0)
++ #define is_a_digit(c) ((((c) >= '0') && ((c) <= '9')) ? 1 : 0)
++ #define is_allowed(c) (is_cquote(c) || is_cword(c) || is_dash(c) || \
++ is_pound(c))
++ #define qs_allowed(a) (((a)->qstype != qsGdb) && ((a)->qstype != qsProg))
++
++ /* Internal justification functions */
++ QSTRING_S *is_quote(char *, char *, int);
++ QSTRING_S *qs_normal_part(QSTRING_S *);
++ QSTRING_S *qs_remove_trailing_spaces(QSTRING_S *);
++ QSTRING_S *trim_qs_from_cl(QSTRING_S *, QSTRING_S *, QSTRING_S *);
++ QSTRING_S *fix_qstring(QSTRING_S *, QSTRING_S *, QSTRING_S *);
++ QSTRING_S *fix_qstring_allowed(QSTRING_S *, QSTRING_S *, QSTRING_S *);
++ QSTRING_S *qs_add(char *, char *, QStrType, int, int, int, int);
++ QSTRING_S *remove_qsword(QSTRING_S *);
++ QSTRING_S *do_raw_quote_match(char *, char *, char *, char *, QSTRING_S **, QSTRING_S **);
++ void free_qs(QSTRING_S **);
++ int word_is_prog(char *);
++ int qstring_is_normal(QSTRING_S *);
++ int exists_good_part(QSTRING_S *);
++ int strcmp_qs(char *, char *);
++ int count_levels_qstring(QSTRING_S *);
++ int same_qstring(QSTRING_S *, QSTRING_S *);
++ int advance_quote_string(char *, char *, int);
++ int isaword(char *,int ,int);
++ int isamailbox(char *,int ,int);
++
++
++ int
++ word_is_prog(char *word)
++ {
++ static char *list1[] = {"#include",
++ "#define",
++ "#ifdef",
++ "#ifndef",
++ "#elif",
++ "#if",
++ NULL};
++ static char *list2[] = {"#else",
++ "#endif",
++ NULL};
++ int i, j = strlen(word), k, rv = 0;
++
++ for(i = 0; rv == 0 && list1[i] && (k = strlen(list1[i])) && k < j; i++)
++ if(!strncmp(list1[i], word, k) && ISspace(word[k]))
++ rv++;
++
++ if(rv)
++ return rv;
++
++ for(i = 0; rv == 0 && list2[i] && (k = strlen(list2[i])) && k <= j; i++)
++ if(!strncmp(list2[i], word, k) && (!word[k] || ISspace(word[k])))
++ rv++;
++
++ return rv;
++ }
++
++ /*
++ * This function creates a qstring pointer with the information that
++ * is_quote handles to it.
++ * Parameters:
++ * qs - User supplied quote string
++ * word - The line of text that the user is trying to read/justify
++ * beginw - Where we need to start copying from
++ * endw - Where we end copying
++ * offset - Any offset in endw that we need to account for
++ * typeqs - type of the string to be created
++ * neednext - boolean, indicating if we need to compute the next field
++ * of leave it NULL
++ *
++ * It is a mistake to call this function if beginw >= endw + offset.
++ * Please note the equality sign in the above inequality (this is because
++ * we always assume that qstring->value != "").
++ */
++ QSTRING_S *
++ qs_add(qs, word, typeqs, beginw, endw, offset, neednext)
++ char *qs;
++ char word[NSTRING];
++ QStrType typeqs;
++ int beginw, endw, offset, neednext;
++ {
++ QSTRING_S *qstring, *nextqs;
++ int i;
++
++ qstring = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qstring, 0, sizeof(QSTRING_S));
++ qstring->qstype = qsNormal;
++
++ if (beginw == 0){
++ beginw = endw + offset;
++ qstring->qstype = typeqs;
++ }
++
++ nextqs = neednext ? is_quote(qs, word+beginw, 1) : NULL;
++
++ qstring->value = (char *) malloc((beginw+1)*sizeof(char));
++ strncpy(qstring->value, word, beginw);
++ qstring->value[beginw] = '\0';
++
++ qstring->next = nextqs;
++
++ return qstring;
++ }
++
++ int
++ qstring_is_normal(cl)
++ QSTRING_S *cl;
++ {
++ for (;cl && (cl->qstype == qsNormal); cl = cl->next);
++ return cl ? 0 : 1;
++ }
++
++ /*
++ * Given a quote string, this function returns the part that is the leading
++ * normal part of it. (the normal part is the part that is tagged qsNormal,
++ * that is to say, the one that is not controversial at all (like qsString
++ * for example).
++ */
++ QSTRING_S *
++ qs_normal_part(cl)
++ QSTRING_S *cl;
++ {
++
++ if (!cl) /* nothing in, nothing out */
++ return cl;
++
++ if (cl->qstype != qsNormal)
++ free_qs(&cl);
++
++ if (cl)
++ cl->next = qs_normal_part(cl->next);
++
++ return cl;
++ }
++
++ /*
++ * this function removes trailing spaces from a quote string, but leaves the
++ * last one if there are trailing spaces
++ */
++ QSTRING_S *
++ qs_remove_trailing_spaces(cl)
++ QSTRING_S *cl;
++ {
++ QSTRING_S *rl = cl;
++ if (!cl) /* nothing in, nothing out */
++ return cl;
++
++ if (cl->next)
++ cl->next = qs_remove_trailing_spaces(cl->next);
++ else{
++ if (value_is_space(cl->value))
++ free_qs(&cl);
++ else{
++ int i, l;
++ i = l = strlen(cl->value) - 1;
++ while (cl->value && cl->value[i]
++ && ISspace(cl->value[i]))
++ i--;
++ i += (i < l) ? 2 : 1;
++ cl->value[i] = '\0';
++ }
++ }
++ return cl;
++ }
++
++ /*
++ * This function returns if two strings are the same quote string.
++ * The call is not symmetric. cl must preceed the line nl. This function
++ * should be called for comparing the last part of cl and nl.
++ */
++ int
++ strcmp_qs(char *valuecl, char *valuenl)
++ {
++ int j;
++
++ for (j = 0; valuecl[j] && (valuecl[j] == valuenl[j]); j++);
++ return !strcmp(valuecl, valuenl)
++ || (valuenl[j] && value_is_space(valuenl+j)
++ && value_is_space(valuecl+j)
++ && strlenis(valuecl+j) >= strlenis(valuenl+j))
++ || (!valuenl[j] && value_is_space(valuecl+j));
++ }
++
++ int
++ count_levels_qstring(cl)
++ QSTRING_S *cl;
++ {
++ int count;
++ for (count = 0; cl ; count++, cl = cl->next);
++
++ return count;
++ }
++
++ int
++ value_is_space(char *value)
++ {
++ for (; value && *value && ISspace(*value); value++);
++
++ return value && *value ? 0 : 1;
++ }
++
++ void
++ free_qs(QSTRING_S **cl)
++ {
++ if (!(*cl))
++ return;
++
++ if ((*cl)->next)
++ free_qs(&((*cl)->next));
++
++ (*cl)->next = (QSTRING_S *) NULL;
++
++ if ((*cl)->value)
++ free((void *)(*cl)->value);
++ (*cl)->value = (char *) NULL;
++ free((void *)(*cl));
++ *cl = (QSTRING_S *) NULL;
++ }
++
++ /*
++ * This function returns the number of agreements between
++ * cl and nl. The call is not symmetric. cl must be the line
++ * preceding nl.
++ */
++ int
++ same_qstring(QSTRING_S *cl, QSTRING_S *nl)
++ {
++ int same = 0, done = 0;
++
++ for (;cl && nl && !done; cl = cl->next, nl = nl->next)
++ if (cl->qstype == nl->qstype
++ && (!strcmp(cl->value, nl->value)
++ || (!cl->next && strcmp_qs(cl->value, nl->value))))
++ same++;
++ else
++ done++;
++ return same;
++ }
++
++ QSTRING_S *
++ trim_qs_from_cl(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
++ {
++ QSTRING_S *cqstring = pl ? pl : nl;
++ QSTRING_S *tl = pl ? pl : nl;
++ int p, c;
++
++ if (qstring_is_normal(tl))
++ return tl;
++
++ p = same_qstring(pl ? pl : cl, pl ? cl : nl);
++
++ for (c = 1; c < p; c++, cl = cl->next, tl = tl->next);
++
++ /*
++ * cl->next and tl->next differ, it may be because cl->next does not
++ * exist or tl->next does not exist or simply both exist but are
++ * different. In this last case, it may be that cl->next->value is made
++ * of spaces. If this is the case, tl advances once more.
++ */
++
++ if (tl->next){
++ if (cl && cl->next && value_is_space(cl->next->value))
++ tl = tl->next;
++ if (tl->next)
++ free_qs(&(tl->next));
++ }
++
++ if (!p)
++ free_qs(&cqstring);
++
++ return cqstring;
++ }
++
++ /* This function trims cl so that it returns a real quote string based
++ * on information gathered from the previous and next lines. pl and cl are
++ * also trimmed, but that is done in another function, not here.
++ */
++ QSTRING_S *
++ fix_qstring(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
++ {
++ QSTRING_S *cqstring = cl, *nqstring = nl, *pqstring = pl;
++ int c, n;
++
++ if (qstring_is_normal(cl))
++ return cl;
++
++ c = count_levels_qstring(cl);
++ n = same_qstring(cl,nl);
++
++ if (!n){ /* no next line or no agreement with next line */
++ int p = same_qstring(pl, cl); /* number of agreements between pl and cl */
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * Here p <= c, so either p < c or p == c. If p == c, we are done,
++ * and return cl. If not, there are two cases, either p == 0 or
++ * 0 < p < c. In the first case, we do not have enough evidence
++ * to return anything other than the normal part of cl, in the second
++ * case we can only return p levels of cl.
++ */
++
++ if (p == c)
++ tl = cqstring;
++ else{
++ if (p){
++ for (c = 1; c < p; c++)
++ cl = cl->next;
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ else{
++ int done = 0;
++ QSTRING_S *al = cl; /* another line */
++ /*
++ * Ok, we reaelly don't have enough evidence to return anything,
++ * different from the normal part of cl, but it could be possible
++ * that we may want to accept the not-normal part, so we better
++ * make an extra test to determine what needs to be freed
++ */
++ while (pl && cl && cl->qstype == pl->qstype
++ && !strucmp(cl->value, pl->value)){
++ cl = cl->next;
++ pl = pl->next;
++ }
++ if (pl && cl && cl->qstype == pl->qstype
++ && strcmp_qs(pl->value, cl->value))
++ cl = cl->next; /* next level differs only in spaces */
++ while (!done){
++ while (cl && cl->qstype == qsNormal)
++ cl = cl->next;
++ if (cl){
++ if ((cl->qstype == qsString)
++ && (cl->value[strlen(cl->value) - 1] == '>'))
++ cl = cl->next;
++ else done++;
++ }
++ else done++;
++ }
++ if (al == cl){
++ free_qs(&(cl));
++ tl = cl;
++ }
++ else {
++ while (al && (al->next != cl))
++ al = al->next;
++ cl = al;
++ if (cl && cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ }
++ }
++ return tl;
++ }
++ if (n + 1 < c){ /* if there are not enough agreements */
++ int p = same_qstring(pl, cl); /* number of agreement between pl and cl */
++ QSTRING_S *tl; /* test line */
++ /*
++ * There's no way we can use cl in this case, but we can use
++ * part of cl, this is if pl does not have more agreements
++ * with cl.
++ */
++ if (p == c)
++ tl = cqstring;
++ else{
++ int m = p < n ? n : p;
++ for (c = 1; c < m; c++){
++ pl = pl ? pl->next : (QSTRING_S *) NULL;
++ nl = nl ? nl->next : (QSTRING_S *) NULL;
++ cl = cl->next;
++ }
++ if (p == n && pl && pl->next && nl && nl->next
++ && ((cl->next->qstype == pl->next->qstype)
++ || (cl->next->qstype == nl->next->qstype))
++ && (strcmp_qs(cl->next->value, pl->next->value)
++ || strcmp_qs(pl->next->value, cl->next->value)
++ || strcmp_qs(cl->next->value, nl->next->value)
++ || strcmp_qs(nl->next->value, cl->next->value)))
++ cl = cl->next; /* next level differs only in spaces */
++ if (cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ return tl;
++ }
++ if (n + 1 == c){
++ int p = same_qstring(pl, cl);
++ QSTRING_S *tl; /* test line */
++
++ /*
++ * p <= c, so p <= n+1, which means p < n + 1 or p == n + 1.
++ * If p < n + 1, then p <= n.
++ * so we have three possibilities:
++ * p == n + 1 or p == n or p < n.
++ * In the first case we copy p == n + 1 == c levels, in the second
++ * and third case we copy n levels, and check if we can copy the
++ * n + 1 == c level.
++ */
++ if (p == n + 1) /* p == c, in the above sense of c */
++ tl = cl; /* use cl, this is enough evidence */
++ else{
++ for (c = 1; c < n; c++)
++ cl = cl->next;
++ /*
++ * Here c == n, we only have one more level of cl, and at least one
++ * more level of nl
++ */
++ if (cl->next->qstype == qsNormal)
++ cl = cl->next;
++ if (cl->next)
++ free_qs(&(cl->next));
++ tl = cqstring;
++ }
++ return tl;
++ }
++ if (n == c) /* Yeah!!! */
++ return cqstring;
++ }
++
++ QSTRING_S *
++ fix_qstring_allowed(QSTRING_S *cl, QSTRING_S *nl, QSTRING_S *pl)
++ {
++ if(!cl)
++ return (QSTRING_S *) NULL;
++
++ if (qs_allowed(cl))
++ cl->next = fix_qstring_allowed(cl->next, (nl ? nl->next : NULL),
++ (pl ? pl->next : NULL));
++ else
++ if((nl && cl->qstype == nl->qstype) || (pl && cl->qstype == pl->qstype)
++ || (!nl && !pl))
++ free_qs(&cl);
++ return cl;
++ }
++
++ /*
++ * This function flattens the quote string returned to us by is_quote. A
++ * crash in this function implies a bug elsewhere.
++ */
++ void
++ flatten_qstring(QSTRING_S *qs, char *buff, int bufflen)
++ {
++ int i, j;
++ if(!buff || bufflen <= 0)
++ return;
++
++ for (i = 0; qs; qs = qs->next)
++ for (j = 0; i < bufflen - 1
++ && (qs->value[j]) && (buff[i++] = qs->value[j]); j++);
++ buff[i] = '\0';
++ }
++
++ /*
++ * Given a string, we return the position where the function thinks that
++ * the quote string is over, if you are ever thinking of fixing something,
++ * you got to the right place. Memory freed by caller. Experience shows
++ * that it only makes sense to initialize memory when we need it, not at
++ * the start of this function.
++ */
++ QSTRING_S *
++ is_quote (char *qs,char *word, int been_here)
++ {
++ int i = 0, j, nxt, prev, finished = 0, offset;
++ unsigned char c;
++ QSTRING_S *qstring = (QSTRING_S *) NULL;
++
++ if (!word || !word[0])
++ return (QSTRING_S *) NULL;
++
++ while (!finished){
++ /*
++ * Before we apply our rules, let's advance past the quote string
++ * given by the user, this will avoid not recognition of the
++ * user's indent string and application of the arbitrary rules
++ * below. Notice that this step may bring bugs into this
++ * procedure, but these bugs will only appear if the indent string
++ * is really really strange and the text to be justified
++ * cooperates a lot too, so in general this will not be a problem.
++ * If you are concerned about this bug, simply remove the
++ * following lines after this comment and before the "switch"
++ * command below and use a more normal quote string!.
++ */
++ i += advance_quote_string(qs, word, i);
++ if (!word[i]) /* went too far? */
++ return qs_add(qs, word, qsNormal, 0, i, 0, 0);
++
++ switch (c = (unsigned char) now(word,i)){
++ case NBSP:
++ case TAB :
++ case ' ' : { QSTRING_S *nextqs, *d;
++
++ for (; ISspace(word[i]); i++); /* FIX ME */
++ nextqs = is_quote(qs,word+i, 1);
++ /*
++ * Merge qstring and nextqs, since this is an artificial
++ * separation, unless nextqs is of different type.
++ * What this means in practice is that if
++ * qs->qstype == qsNormal and qs->next != NULL, then
++ * qs->next->qstype != qsNormal.
++ *
++ * Can't use qs_add to merge because it could lead
++ * to an infinite loop (e.g a line "^ ^").
++ */
++ i += nextqs && nextqs->qstype == qsNormal
++ ? strlen(nextqs->value) : 0;
++ qstring = (QSTRING_S *) malloc (sizeof(QSTRING_S));
++ memset (qstring, 0, sizeof(QSTRING_S));
++ qstring->value = (char *) malloc((i+1)*sizeof(char));
++ strncpy(qstring->value, word, i);
++ qstring->value[i] = '\0';
++ qstring->qstype = qsNormal;
++ if(nextqs && nextqs->qstype == qsNormal){
++ d = nextqs->next;
++ nextqs->next = NULL;
++ qstring->next = d;
++ free_qs(&nextqs);
++ }
++ else
++ qstring->next = nextqs;
++
++ return qstring;
++ }
++ break;
++ case RPAREN: /* parenthesis ')' */
++ if ((i != 0) || ((i == 0) && been_here))
++ i++;
++ else
++ if (i == 0)
++ return qs_add(qs, word, qsChar, i, i, 1, 1);
++ else
++ finished++;
++ break;
++
++ case ':': /* colon */
++ case '~': nxt = next(word,i);
++ if ((is_tilde(c) && (nxt == '/'))
++ || (is_colon(c) && !is_cquote(nxt)
++ && !is_cword(nxt) && nxt != RPAREN))
++ finished++;
++ else if (is_cquote(c)
++ || is_cquote(nxt)
++ || (c != '~' && nxt == RPAREN)
++ || (i != 0 && ISspace(nxt))
++ || is_cquote(prev = before(word,i))
++ || (ISspace(prev) && !is_tilde(c))
++ || (is_tilde(c) && nxt != '/'))
++ i++;
++ else if (i == 0 && been_here)
++ return qs_add(qs, word, qsChar, i, i, 1, 1);
++ else
++ finished++;
++ break;
++
++ case '<' :
++ case '=' :
++ case '-' : offset = is_cquote(nxt = next(word,i)) ? 2
++ : (nxt == c && is_cquote(next(word,i+1))) ? 3 : -1;
++
++ if (offset > 0)
++ return qs_add(qs, word, qsString, i, i, offset, 1);
++ else
++ finished++;
++ break;
++
++ case '[' :
++ case '+' : /* accept +>, *> */
++ case '*' : if (is_rarrow(nxt = next(word, i)) || /* stars */
++ (ISspace(nxt) && is_rarrow(next(word,i+1))))
++ i++;
++ else
++ finished++;
++ break;
++
++ case '^' :
++ case '!' :
++ case '%' : if (next(word,i) != c)
++ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
++ else
++ finished++;
++ break;
++
++ case '_' : if(ISspace(next(word, i)))
++ return qs_add(qs, word, qsChar, i, i+1, 0, 1);
++ else
++ finished++;
++ break;
++
++ case '#' : { QStrType qstype = qsChar;
++ if((nxt = next(word, i)) != c){
++ if(isdigit((int) nxt))
++ qstype = qsGdb;
++ else
++ if(word_is_prog(word))
++ qstype = qsProg;
++ return qs_add(qs, word, qstype, i, i+1, 0, 1);
++ }
++ else
++ finished++;
++ break;
++ }
++
++ default:
++ if (is_cquote(c))
++ i++;
++ else if (is_cletter(c)){
++ for (j = i; (is_cletter(nxt = next(word,j)) || is_cnumber(nxt))
++ && !(ISspace(nxt));j++);
++ /*
++ * The whole reason why we are splitting the quote
++ * string is so that we will be able to accept quote
++ * strings that are strange in some way. Here we got to
++ * a point in which a quote string might exist, but it
++ * could be strange, so we need to create a "next" field
++ * for the quote string to warn us that something
++ * strange is coming. We need to confirm if this is a
++ * good choice later. For now we will let it pass.
++ */
++ if (isaword(word,i,j) || isamailbox(word,i,j)){
++ int offset;
++ QStrType qstype;
++
++ offset = (is_cquote(c = next(word,j))
++ || (c == RPAREN)) ? 2
++ : ((ISspace(c)
++ && is_cquote(next(word,j+1))) ? 3 : -1);
++
++ qstype = (is_cquote(c) || (c == RPAREN))
++ ? (is_qsword(c) ? qsWord : qsString)
++ : ((ISspace(c) && is_cquote(next(word,j+1)))
++ ? (is_qsword(next(word,j+1))
++ ? qsWord : qsString)
++ : qsString);
++
++ /*
++ * qsWords are valid quote strings only when
++ * they are followed by text.
++ */
++ if (offset > 0 && qstype == qsWord &&
++ !allwd_after_qsword(now(word,j + offset)))
++ offset = -1;
++
++ if (offset > 0)
++ return qs_add(qs, word, qstype, i, j, offset, 1);
++ }
++ finished++;
++ }
++ else{
++ if(i > 0)
++ return qs_add(qs, word, qsNormal, 0, i, 0, 1);
++ else if(!forbidden(c))
++ return qs_add(qs, word, qsChar, 0, 1, 0, 1);
++ else /* chao pescao */
++ finished++;
++ }
++ break;
++ } /* End Switch */
++ } /* End while */
++ if (i > 0)
++ qstring = qs_add(qs, word, qsNormal, 0, i, 0, 0);
++ return qstring;
++ }
++
++ int
++ isaword(word,i,j)
++ char word[NSTRING];
++ int i;
++ int j;
++ {
++ return i <= j && is_cletter(word[i]) ?
++ (i < j ? isaword(word,i+1,j) : 1) : 0;
++ }
++
++ int
++ isamailbox(word,i,j)
++ char word[NSTRING];
++ int i, j;
++ {
++ return i <= j && (is_cletter(word[i]) || is_a_digit(word[i])
++ || word[i] == '.')
++ ? (i < j ? isamailbox(word,i+1,j) : 1) : 0;
++ }
++
++ /*
++ This routine removes the last part that is qsword or qschar that is not
++ followed by a normal part. This means that if a qsword or qschar is
++ followed by a qsnormal (or qsstring), we accept the qsword (or qschar)
++ as part of a quote string.
++ */
++ QSTRING_S *
++ remove_qsword(cl)
++ QSTRING_S *cl;
++ {
++ QSTRING_S *np = cl;
++ QSTRING_S *cp = np; /* this variable trails cl */
++
++ while(1){
++ while (cl && cl->qstype == qsNormal)
++ cl = cl->next;
++
++ if (cl){
++ if (((cl->qstype == qsWord) || (cl->qstype == qsChar))
++ && !exists_good_part(cl)){
++ if (np == cl) /* qsword or qschar at the beginning */
++ free_qs(&cp);
++ else{
++ while (np->next != cl)
++ np = np->next;
++ free_qs(&(np->next));
++ }
++ break;
++ }
++ else
++ cl = cl->next;
++ }
++ else
++ break;
++ }
++ return cp;
++ }
++
++ int
++ exists_good_part (cl)
++ QSTRING_S *cl;
++ {
++ return (cl ? (((cl->qstype != qsWord) && (cl->qstype != qsChar)
++ && qs_allowed(cl) && !value_is_space(cl->value))
++ ? 1 : exists_good_part(cl->next))
++ : 0);
++ }
++
++ int
++ line_isblank(char *q, char *GLine, char *NLine, char *PLine, int buflen)
++ {
++ int n = 0;
++ QSTRING_S *cl;
++ char qstr[NSTRING];
++
++ cl = do_raw_quote_match(q, GLine, NLine, PLine, NULL, NULL);
++
++ flatten_qstring(cl, qstr, NSTRING);
++
++ free_qs(&cl);
++
++ for(n = strlen(qstr); n < buflen && GLine[n]; n++)
++ if(!ISspace((unsigned char) GLine[n]))
++ return(FALSE);
++
++ return(TRUE);
++ }
++
++ QSTRING_S *
++ do_raw_quote_match(char *q, char *GLine, char *NLine, char *PLine, QSTRING_S **nlp, QSTRING_S **plp)
++ {
++ QSTRING_S *cl, *nl = NULL, *pl = NULL;
++ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
++ int emptypl = 0, emptynl = 0;
++
++ if (!(cl = is_quote(q, GLine, 0))) /* if nothing in, nothing out */
++ return cl;
++
++ nl = is_quote(q, NLine, 0); /* Next Line */
++ if (nlp) *nlp = nl;
++ pl = is_quote(q, PLine, 0); /* Previous Line */
++ if (plp) *plp = pl;
++ /*
++ * If there's nothing in the preceeding or following line
++ * there is not enough information to accept it or discard it. In this
++ * case it's likely to be an isolated line, so we better accept it
++ * if it does not look like a word.
++ */
++ flatten_qstring(pl, pbuf, NSTRING);
++ emptypl = (!PLine || !PLine[0] ||
++ (pl && value_is_space(pbuf)) && !PLine[strlen(pbuf)]) ? 1 : 0;
++ if (emptypl){
++ flatten_qstring(nl, nbuf, NSTRING);
++ emptynl = (!NLine || !NLine[0] ||
++ (nl && value_is_space(nbuf) && !NLine[strlen(nbuf)])) ? 1 : 0;
++ if (emptynl){
++ cl = remove_qsword(cl);
++ if((cl = fix_qstring_allowed(cl, NULL, NULL)) != NULL)
++ cl = qs_remove_trailing_spaces(cl);
++ free_qs(&nl);
++ free_qs(&pl);
++ if(nlp) *nlp = NULL;
++ if(plp) *plp = NULL;
++
++ return cl;
++ }
++ }
++
++ /*
++ * If either cl, nl or pl contain suspicious characters that may make
++ * them (or not) be quote strings, we need to fix them, so that the
++ * next pass will be done correctly.
++ */
++
++ cl = fix_qstring(cl, nl, pl);
++ nl = trim_qs_from_cl(cl, nl, NULL);
++ pl = trim_qs_from_cl(cl, NULL, pl);
++ if((cl = fix_qstring_allowed(cl, nl, pl)) != NULL){
++ nl = trim_qs_from_cl(cl, nl, NULL);
++ pl = trim_qs_from_cl(cl, NULL, pl);
++ }
++ else{
++ free_qs(&nl);
++ free_qs(&pl);
++ }
++ if(nlp)
++ *nlp = nl;
++ else
++ free_qs(&nl);
++ if(plp)
++ *plp = pl;
++ else
++ free_qs(&pl);
++ return cl;
++ }
++
++ QSTRING_S *
++ do_quote_match(q, GLine, NLine, PLine, rqstr, rqstrlen, plb)
++ char *q, *GLine, *NLine, *PLine, *rqstr;
++ int rqstrlen, plb;
++ {
++ QSTRING_S *cl, *nl = NULL, *pl = NULL;
++ int c, n, p,i, j, NewP, NewC, NewN, clength, same = 0;
++ char nbuf[NSTRING], pbuf[NSTRING], buf[NSTRING];
++
++ if(rqstr)
++ *rqstr = '\0';
++
++ /* if nothing in, nothing out */
++ cl = do_raw_quote_match(q, GLine, NLine, PLine, &nl, &pl);
++ if(cl == NULL){
++ free_qs(&nl);
++ free_qs(&pl);
++ return cl;
++ }
++
++ flatten_qstring(cl, rqstr, rqstrlen);
++ flatten_qstring(cl, buf, NSTRING);
++ flatten_qstring(nl, nbuf, NSTRING);
++ flatten_qstring(pl, pbuf, NSTRING);
++
++ /*
++ * Once upon a time, is_quote used to return the length of the quote
++ * string that it had found. One day, not long ago, black hand came
++ * and changed all that, and made is_quote return a quote string
++ * divided in several fields, making the algorithm much more
++ * complicated. Fortunately black hand left a few comments in the
++ * source code to make it more understandable. Because of this change
++ * we need to compute the lengths of the quote strings separately
++ */
++ c = buf && buf[0] ? strlen(buf) : 0;
++ n = nbuf && nbuf[0] ? strlen(nbuf) : 0;
++ p = pbuf && pbuf[0] ? strlen(pbuf) : 0;
++ /*
++ * When quote strings contain only blank spaces (ascii code 32) the
++ * above count is equal to the length of the quote string, but if
++ * there are TABS, the length of the quote string as seen by the user
++ * is different than the number that was just computed. Because of
++ * this we demand a recount (hmm.. unless you are in Florida, where
++ * recounts are forbidden)
++ */
++ NewP = strlenis(pbuf);
++ NewC = strlenis(buf);
++ NewN = strlenis(nbuf);
++
++ /*
++ * For paragraphs with spaces in the first line, but no space in the
++ * quote string of the second line, we make sure we choose the quote
++ * string without a space at the end of it.
++ */
++ if ((NLine && !NLine[0])
++ && ((PLine && !PLine[0])
++ || (((same = same_qstring(pl, cl)) != 0)
++ && (same != count_levels_qstring(cl)))))
++ cl = qs_remove_trailing_spaces(cl);
++ else
++ if (NewC > NewN){
++ int agree = 0;
++ for (j = 0; (j < n) && (GLine[j] == NLine[j]); j++);
++ clength = j;
++ /* clength is the common length in which Gline and Nline agree */
++ /* j < n means that they do not agree fully */
++ /* GLine = " \tText"
++ NLine = " Text" */
++ if(j == n)
++ agree++;
++ if (clength < n){ /* see if buf and nbuf are padded with spaces and tabs */
++ for (i = clength; i < n && ISspace(NLine[i]); i++);
++ if (i == n){/* padded NLine until the end of spaces? */
++ for (i = clength; i < c && ISspace(GLine[i]); i++);
++ if (i == c) /* Padded CLine until the end of spaces? */
++ agree++;
++ }
++ }
++ if (agree){
++ for (j = clength; j < c && ISspace(GLine[j]); j++);
++ if (j == c){
++ /*
++ * If we get here, it means that the current line has the same
++ * quote string (visually) than the next line, but both of them
++ * are padded with different amount of TABS or spaces at the end.
++ * The current line (GLine) has more spaces/TABs than the next
++ * line. This is the typical situation that is found at the
++ * begining of a paragraph. We need to check this, however, by
++ * checking the previous line. This avoids that we confuse
++ * ourselves with being in the last line of a paragraph.
++ * Example when it should not free_qs(cl)
++ * " Text in Paragraph 1" (PLine)
++ * " Text in Paragraph 1" (GLine)
++ * " Other Paragraph Number 2" (NLine)
++ *
++ * Example when it should free_qs(cl):
++ * ":) " (PLine) p = 3, j = 3
++ * ":) Text" (GLine) c = 5
++ * ":) More text" (NLine) n = 3
++ *
++ * Example when it should free_qs(cl):
++ * ":) " (PLine) p = 3, j = 3
++ * ":) > > > Text" (GLine) c = 11
++ * ":) > > > More text" (NLine) n = 9
++ *
++ * Example when it should free_qs(cl):
++ * ":) :) " (PLine) p = 6, j = 3
++ * ":) > > > Text" (GLine) c = 11
++ * ":) > > > More text" (NLine) n = 9
++ *
++ * Example when it should free_qs(cl):
++ * ":) > > > " (PLine) p = 13, j = 11
++ * ":) > > > Text" (GLine) c = 11
++ * ":) > > > More text" (NLine) n = 9
++ *
++ * The following example is very interesting. The "Other Text"
++ * line below should free the quote string an make it equal to the
++ * quote string of the line below it, but any algorithm trying
++ * to advance past that line should make it stop there, so
++ * we need one more check, to check the raw quote string and the
++ * processed quote string at the same time.
++ * FREE qs in this example.
++ * " Some Text" (PLine) p = 3, j = 0
++ * "\tOther Text" (GLine) c = 1
++ * " More Text" (NLine) n = 3
++ *
++ */
++ for (j = 0; (j < p) && (GLine[j] == PLine[j]); j++);
++ if ((p != c || j != p) && NLine[n])
++ if(!get_indent_raw_line(q, PLine, nbuf, NSTRING, p, plb)
++ || NewP + strlenis(nbuf) != NewC){
++ free_qs(&cl);
++ free_qs(&pl);
++ return nl;
++ }
++ }
++ }
++ }
++
++ free_qs(&nl);
++ free_qs(&pl);
++
++ return cl;
++ }
++
++ /*
++ * Given a line, an initial position, and a quote string, we advance the
++ * current line past the quote string, including arbitraty spaces
++ * contained in the line, except that it removes trailing spaces. We do
++ * not handle TABs, if any, contained in the quote string. At least not
++ * yet.
++ *
++ * Arguments: q - quote string
++ * l - a line to process
++ * i - position in the line to start processing. i = 0 is the
++ * begining of that line.
++ */
++ int
++ advance_quote_string(q, l, i)
++ char *q;
++ char l[NSTRING];
++ int i;
++ {
++ int n = 0, j = 0, is = 0, es = 0;
++ int k, m, p, adv;
++ char qs[NSTRING] = {'\0'};
++ if(!q || !*q)
++ return(0);
++ for (p = strlen(q); (p > 0) && (q[p - 1] == ' '); p--, es++);
++ if (!p){ /* string contains only spaces */
++ for (k = 0; ISspace(l[i + k]); k++);
++ k -= k % es;
++ return k;
++ }
++ for (is = 0; ISspace(q[is]); is++); /* count initial spaces */
++ for (m = 0 ; is + m < p ; m++)
++ qs[m] = q[is + m]; /* qs = quote string without any space at the end */
++ /* advance as many spaces as there are at the begining */
++ for (k = 0; ISspace(l[i + j]); k++, j++);
++ /* now find the visible string in the line */
++ for (m = 0; qs[m] && l[i + j] == qs[m]; m++, j++);
++ if (!qs[m]){ /* no match */
++ /*
++ * So far we have advanced at least "is" spaces, plus the visible
++ * string "qs". Now we need to advance the trailing number of
++ * spaces "es". If we can do that, we have found the quote string.
++ */
++ for (p = 0; ISspace(l[i + j + p]); p++);
++ adv = advance_quote_string(q, l, i + j + ((p < es) ? p : es));
++ n = ((p < es) ? 0 : es) + k + m + adv;
++ }
++ return n;
++ }
++
++ /*
++ * This function returns the effective length in screen of the quote
++ * string. If the string contains a TAB character, it is added here, if
++ * not, the length returned is the length of the string
++ */
++ int strlenis(char *qstr)
++ {
++ int i, rv = 0;
++ for (i = 0; qstr && qstr[i]; i++)
++ rv += ((qstr[i] == TAB) ? (~rv & 0x07) + 1 : 1);
++ return rv;
++ }
++
++ int
++ is_indent (word, plb)
++ char word[NSTRING];
++ int plb;
++ {
++ int i = 0, finished = 0, c, nxt, j, k, digit = 0, bdigits = -1, alpha = 0;
++
++ if (!word || !word[0])
++ return i;
++
++ for (i = 0, j = 0; ISspace(word[i]); i++, j++);
++ while ((i < NSTRING - 2) && !finished){
++ switch (c = now(word,i)){
++ case NBSP:
++ case TAB :
++ case ' ' : for (; ISspace(word[i]); i++);
++ if (!is_indent_char(now(word,i)))
++ finished++;
++ break;
++
++ case '+' :
++ case '.' :
++ case ']' :
++ case '*' :
++ case '}' :
++ case '-' :
++ case RPAREN:
++ nxt = next(word,i);
++ if ((c == '.' && allowed_after_period(nxt) && alpha)
++ || (c == '*' && allowed_after_star(nxt))
++ || (c == '}' && allowed_after_braces(nxt))
++ || (c == '-' && allowed_after_dash(nxt))
++ || (c == '+' && allowed_after_dash(nxt))
++ || (c == RPAREN && allowed_after_parenth(nxt))
++ || (c == ']' && allowed_after_parenth(nxt)))
++ i++;
++ else
++ finished++;
++ break;
++
++ default : if (is_a_digit(c) && plb){
++ if (bdigits < 0)
++ bdigits = i; /* first digit */
++ for (k = i; is_a_digit(now(word,k)); k++);
++ if (k - bdigits > 2){ /* more than 2 digits? */
++ i = bdigits; /* too many! */
++ finished++;
++ }
++ else{
++ if(allowed_after_digit(now(word,k),word,k)){
++ alpha++;
++ i = k;
++ }
++ else{
++ i = bdigits;
++ finished++;
++ }
++ }
++ }
++ else
++ finished++;
++ break;
++
++ }
++ }
++ if (i == j)
++ i = 0; /* there must be something more than spaces in an indent string */
++ return i;
++ }
++
++ int
++ get_indent_raw_line(char *q, char *GLine, char *buf, int buflen, int k, int plb)
++ {
++ int i, j;
++
++ i = is_indent(GLine+k, plb);
++
++ for (j = 0; j < i && j < buflen && (buf[j] = GLine[j + k]); j++);
++ buf[j] = '\0';
++
++ return i;
++ }
++
+diff -rc alpine-1.10/pith/osdep/color.h alpine-1.10.fillpara/pith/osdep/color.h
+*** alpine-1.10/pith/osdep/color.h 2007-05-08 16:38:08.000000000 -0700
+--- alpine-1.10.fillpara/pith/osdep/color.h 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 43,48 ****
+--- 43,69 ----
+ #define PSC_REV 0x2
+ #define PSC_RET 0x4 /* return an allocated copy of previous color */
+
++ /*
++ * struct that will help us determine what the quote string of a line
++ * is. The "next" field indicates the presence of a possible continuation.
++ * The idea is that if a continuation fails, we free it and check for the
++ * remaining structure left
++ */
++
++ typedef enum {qsNormal, qsString, qsWord, qsChar,
++ qsGdb, qsProg, qsText} QStrType;
++
++ typedef struct QSTRING {
++ char *value; /* possible quote string */
++ QStrType qstype; /* type of quote string */
++ struct QSTRING *next; /* possible continuation */
++ } QSTRING_S;
++
++ #define UCH(c) ((unsigned char) (c))
++ #define NBSP UCH('\240')
++ #define ISspace(c) (UCH(c) == ' ' || UCH(c) == TAB || UCH(c) == NBSP)
++
++
+
+ /*
+ * MATCH_NORM_COLOR means that the color that is set to this value
+***************
+*** 95,100 ****
+--- 116,126 ----
+ char *pico_get_last_bg_color(void);
+ char *color_to_canonical_name(char *);
+ int pico_count_in_color_table(void);
++ int is_indent(char *, int);
++ int get_indent_raw_line (char *, char *, char *, int, int, int);
++ int line_isblank(char *, char *, char *, char *, int);
++ int strlenis(char *);
++ int value_is_space(char *);
+
+
+ #endif /* PITH_OSDEP_COLOR_INCLUDED */
+diff -rc alpine-1.10/pith/pine.hlp alpine-1.10.fillpara/pith/pine.hlp
+*** alpine-1.10/pith/pine.hlp 2008-03-14 11:34:08.000000000 -0700
+--- alpine-1.10.fillpara/pith/pine.hlp 2008-05-19 16:31:06.000000000 -0700
+***************
+*** 6408,6413 ****
+--- 6408,6453 ----
+ "type the character ^".
+
+ <P>
++ This version of Alpine contains an enhanced algorithm for justification,
++ which allows you to justify text that contains more complicated quote
++ strings. This algorithm is based on pragmatics, rather than on a theory,
++ and seems to work well with most messages. Below you will find technical
++ information on how this algorithm works.
++
++ <P>
++ When justifying, Alpine goes through each line of the text and tries to
++ determine for each line what the quote string of that line is. The quote
++ string you provided is always recognized. Among other characters
++ recognized is ">".
++
++ <P>
++ Some other constructions of quote strings are recognized only if they
++ appear enough in the text. For example "Peter :" is only
++ recognized if it appears in two consecutive lines.
++
++ <P>
++ Additionaly, Alpine recognizes indent-strings and justifies text in a
++ paragraph to the right of indent-string, padding with spaces if necessary.
++ An indent string is one which you use to delimit e