diff options
author | Eduardo Chappa <chappa@washington.edu> | 2013-05-31 17:08:22 -0600 |
---|---|---|
committer | Eduardo Chappa <chappa@washington.edu> | 2013-05-31 17:08:22 -0600 |
commit | 81e994d7907f850506ddc248f84761a54995e58c (patch) | |
tree | 3bc4993b48ddeec45dee51323437200ab975887c /pico | |
parent | 077522d7e058133f9de99d0d74481566b21c5a98 (diff) | |
download | alpine-81e994d7907f850506ddc248f84761a54995e58c.tar.xz |
* Fix not allow remote execution by adding PIPE_NOSHELL to the opening of a url by
a browser.
Diffstat (limited to 'pico')
-rw-r--r-- | pico/basic.c | 378 | ||||
-rw-r--r-- | pico/blddate.c | 8 | ||||
-rw-r--r-- | pico/composer.c | 20 | ||||
-rw-r--r-- | pico/display.c | 54 | ||||
-rw-r--r-- | pico/ebind.h | 8 | ||||
-rw-r--r-- | pico/edef.h | 2 | ||||
-rw-r--r-- | pico/efunc.h | 12 | ||||
-rw-r--r-- | pico/fileio.c | 6 | ||||
-rw-r--r-- | pico/line.c | 8 | ||||
-rw-r--r-- | pico/main.c | 24 | ||||
-rw-r--r-- | pico/osdep/color.h | 4 | ||||
-rw-r--r-- | pico/osdep/getkey.c | 10 | ||||
-rw-r--r-- | pico/osdep/terminal.c | 13 | ||||
-rw-r--r-- | pico/pico.c | 37 | ||||
-rw-r--r-- | pico/pico.h | 3 | ||||
-rw-r--r-- | pico/random.c | 5 | ||||
-rw-r--r-- | pico/search.c | 67 | ||||
-rw-r--r-- | pico/word.c | 334 |
18 files changed, 873 insertions, 120 deletions
diff --git a/pico/basic.c b/pico/basic.c index 49b04bd6..4479d099 100644 --- a/pico/basic.c +++ b/pico/basic.c @@ -26,9 +26,10 @@ static char rcsid[] = "$Id: basic.c 831 2007-11-27 01:04:19Z hubert@u.washington * 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 @@ -285,7 +286,7 @@ int gotobop(int f, int n) { int quoted, qlen; - UCS qstr[NLINE], qstr2[NLINE]; + char qstr[NLINE], qstr2[NLINE], ind_str[NLINE], pqstr[NLINE];; if (n < 0) /* the other way...*/ return(gotoeop(f, -n)); @@ -297,6 +298,14 @@ gotobop(int f, int n) curwp->w_dotp = lback(curwp->w_dotp); curwp->w_doto = 0; } + + if (indent_match(default_qstr(glo_quote_str, 1), 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> @@ -304,20 +313,58 @@ gotobop(int f, int n) * 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; + quoted = quote_match(default_qstr(glo_quote_str, 1), 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 - && (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 != ' ') + && (quoted == quote_match(default_qstr(glo_quote_str, 1), + lback(curwp->w_dotp), qstr2, NLINE, 0)) + && !strcmp(qstr, qstr2) /* processed string */ + && (quoted == quote_match(default_qstr(glo_quote_str, 1), + lback(curwp->w_dotp), qstr2, NLINE, 1)) + && !strcmp(qstr, qstr2) /* raw string */ + && !indent_match(default_qstr(glo_quote_str, 1), + lback(curwp->w_dotp),ind_str, NLINE, 0) + && !ISspace(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(glo_quote_str, 1), curwp->w_dotp, qstr, NLINE, 1); + quote_match(default_qstr(glo_quote_str, 1), 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(glo_quote_str, 1), 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(glo_quote_str, 1), + lback(curwp->w_dotp), pqstr, NLINE, 0)) + && !strcmp(qstr, pqstr) + && !ISspace(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) @@ -330,7 +377,7 @@ gotobop(int f, int n) else{ /* leave cursor on first word in para */ curwp->w_doto = 0; - while(ucs4_isspace(lgetc(curwp->w_dotp, curwp->w_doto).c)) + 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); @@ -344,6 +391,189 @@ gotobop(int f, int n) return(TRUE); } +unsigned char GetAccent() +{ + UCS c,d; + c = GetKey(); + if ((c == '?') || (c == '!')) { + d = c; + c = '\\'; + } + else + if ((c == 's') || (c == 'S')){ + c = d = 's'; + } + else + if ((c == 'l') || (c == 'L')){ + c = d = 'l'; + } + else + d = GetKey(); + return accent(c,d); +} + +int pineaccent(f,n) + int f,n; +{ unsigned char e; + + if (e = GetAccent()) + execute(e, 0, 1); + return 1; +} + +unsigned char accent(f,n) +UCS f,n; +{ UCS c,d; + + c = f; + d = n; + switch(c){ + case '~' : + switch(d){ + case 'a' : return '\343'; + case 'n' : return '\361'; + case 'o' : return '\365'; + case 'A' : return '\303'; + case 'N' : return '\321'; + case 'O' : return '\325'; + } + break; + case '\047' : + switch(d){ + case 'a' : return '\341'; + case 'e' : return '\351'; + case 'i' : return '\355'; + case 'o' : return '\363'; + case 'u' : return '\372'; + case 'y' : return '\375'; + case 'A' : return '\301'; + case 'E' : return '\311'; + case 'I' : return '\315'; + case 'O' : return '\323'; + case 'U' : return '\332'; + case 'Y' : return '\335'; + } + break; + case '"' : + switch(d){ + case 'a' : return '\344'; + case 'e' : return '\353'; + case 'i' : return '\357'; + case 'o' : return '\366'; + case 'u' : return '\374'; + case 'y' : return '\377'; + case 'A' : return '\304'; + case 'E' : return '\313'; + case 'I' : return '\317'; + case 'O' : return '\326'; + case 'U' : return '\334'; + } + break; + case '^' : + switch(d){ + case 'a' : return '\342'; + case 'e' : return '\352'; + case 'i' : return '\356'; + case 'o' : return '\364'; + case 'u' : return '\373'; + case 'A' : return '\302'; + case 'E' : return '\312'; + case 'I' : return '\316'; + case 'O' : return '\324'; + case 'U' : return '\333'; + case '0' : return '\260'; + case '1' : return '\271'; + case '2' : return '\262'; + case '3' : return '\263'; + } + break; + case '`' : + switch(d){ + case 'a' : return '\340'; + case 'e' : return '\350'; + case 'i' : return '\354'; + case 'o' : return '\362'; + case 'u' : return '\371'; + case 'A' : return '\300'; + case 'E' : return '\310'; + case 'I' : return '\314'; + case 'O' : return '\322'; + case 'U' : return '\331'; + } + break; + case 'o' : + switch(d){ + case 'a' : return '\345'; + case 'A' : return '\305'; + case '/' : return '\370'; + case 'r' : return '\256'; + case 'R' : return '\256'; + case 'c' : return '\251'; + case 'C' : return '\251'; + } + break; + case '-' : + switch(d){ + case 'o' : return '\272'; + case 'O' : return '\272'; + case '0' : return '\272'; + case 'a' : return '\252'; + case 'A' : return '\252'; + case 'l' : return '\243'; + case 'L' : return '\243'; + } + break; + case 'O' : + switch(d){ + case '/' : return '\330'; + case 'r' : return '\256'; + case 'R' : return '\256'; + case 'c' : return '\251'; + case 'C' : return '\251'; + } + case '/' : + switch(d){ + case 'o' : return '\370'; + case 'O' : return '\330'; + } + break; + case 'a' : + switch(d){ + case 'e' : return '\346'; + case 'E' : return '\346'; + } + break; + case 'A' : + switch(d){ + case 'E' : return '\306'; + case 'e' : return '\306'; + } + break; + case ',' : + switch(d){ + case 'c' : return '\347'; + case 'C' : return '\307'; + } + break; + case '\\' : + switch(d){ + case '?' : return '\277'; + case '!' : return '\241'; + } + break; + case 's' : + switch(d){ + case 's' : return '\337'; + } + break; + case 'l' : + switch(d){ + case 'l' : return '\243'; + } + break; + } + return '\0'; +} /* * go forword to the end of the current paragraph @@ -353,8 +583,9 @@ gotobop(int f, int n) int gotoeop(int f, int n) { - int quoted, qlen; - UCS qstr[NLINE], qstr2[NLINE]; + 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)); @@ -367,27 +598,70 @@ gotoeop(int f, int n) 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(glo_quote_str, 1), curwp->w_dotp, qstr, NLINE, 1); + quote_match(default_qstr(glo_quote_str, 1), lforw(curwp->w_dotp), qstr2, NLINE, 1); + indented = indent_match(default_qstr(glo_quote_str, 1), 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(glo_quote_str, 1), 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. */ - quoted = glo_quote_str - ? quote_match(glo_quote_str, - curwp->w_dotp, qstr, NLINE) : 0; - qlen = quoted ? ucs4_strlen(qstr) : 0; + /* 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(glo_quote_str, 1), curwp->w_dotp, qstr, NLINE, fli); + qlen = quoted ? 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 != ' ') + && (quoted == quote_match(default_qstr(glo_quote_str, 1), + lforw(curwp->w_dotp), qstr2, NLINE, fli)) + && !strcmp(qstr, qstr2) + && (quoted == quote_match(default_qstr(glo_quote_str, 1), + lforw(curwp->w_dotp), qstr2, NLINE, 1)) + && !strcmp(qstr, qstr2) + && !indent_match(default_qstr(glo_quote_str, 1), + lforw(curwp->w_dotp), ind_str, NLINE, 0) + && !ISspace(lgetc(lforw(curwp->w_dotp), qlen).c)) curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_doto = llength(curwp->w_dotp); @@ -684,7 +958,57 @@ scrolldownline(int f, int n) return (scrollforw (1, FALSE)); } +/* deltext deletes from the specified position until the end of the file + * or until the signature (when called from Pine), whichever comes first. + */ +int +deltext (f,n) +int f,n; +{ + LINE *currline = curwp->w_dotp; + static int firsttime = 0; + + if ((lastflag&CFKILL) == 0) + kdelete(); + + curwp->w_markp = curwp->w_dotp; + curwp->w_marko = curwp->w_doto; + + while (curwp->w_dotp != curbp->b_linep){ + if ((Pmaster) + && (llength(curwp->w_dotp) == 3) + && (lgetc(curwp->w_dotp, 0).c == '-') + && (lgetc(curwp->w_dotp, 1).c == '-') + && (lgetc(curwp->w_dotp, 2).c == ' ')){ + if (curwp->w_dotp == currline){ + if (curwp->w_doto) + curwp->w_dotp = lforw(curwp->w_dotp); + else + break; + } + else{ + curwp->w_dotp = lback(curwp->w_dotp); + curwp->w_doto = llength(curwp->w_dotp); + break; + } + } + else{ + if(lforw(curwp->w_dotp) != curbp->b_linep) + curwp->w_dotp = lforw(curwp->w_dotp); + else{ + curwp->w_doto = llength(curwp->w_dotp); + break; + } + } + } + killregion(FALSE,1); + lastflag |= CFKILL; + if(firsttime == 0) + emlwrite("Deleted text can be recovered with the ^U command", NULL); + firsttime = 1; + return TRUE; +} /* * Scroll to a position. diff --git a/pico/blddate.c b/pico/blddate.c index 00f0b558..5797c3c5 100644 --- a/pico/blddate.c +++ b/pico/blddate.c @@ -19,7 +19,7 @@ main(argc, argv) char **argv; { struct tm *t; - FILE *outfile=stdout; + FILE *outfile=stdout, *infile; time_t ltime; if(argc > 1 && (outfile = fopen(argv[1], "w")) == NULL){ @@ -46,6 +46,12 @@ main(argc, argv) 1900 + t->tm_year); fprintf(outfile, "char hoststamp[]=\"random-pc\";\n"); + if((infile = fopen("../patchlevel", "r")) != NULL){ + int c; + while ((c = getc(infile)) != EOF) putc(c, outfile); + fclose(infile); + } + else fprintf(outfile, "char plevstamp[]=\"No information available\";\n"); fclose(outfile); diff --git a/pico/composer.c b/pico/composer.c index c801d385..e709cd67 100644 --- a/pico/composer.c +++ b/pico/composer.c @@ -1872,6 +1872,8 @@ AppendAttachment(char *fn, char *sz, char *cmt) } UpdateHeader(0); + if(sendnow) + return(status !=0); PaintHeader(COMPOSER_TOP_LINE, status != 0); PaintBody(1); return(status != 0); @@ -2015,7 +2017,7 @@ LineEdit(int allowedit, UCS *lastch) tbufp = &strng[ods.p_len]; if(VALID_KEY(ch)){ /* char input */ - /* +insert_char:/* * if we are allowing editing, insert the new char * end up leaving tbufp pointing to newly * inserted character in string, and offset to the @@ -2095,6 +2097,13 @@ LineEdit(int allowedit, UCS *lastch) } else { /* interpret ch as a command */ switch (ch = normalize_cmd(ch, ckm, 2)) { + case (CTRL|'\\') : + if (ch = GetAccent()) + goto insert_char; + else + clearcursor(); + break; + case (CTRL|KEY_LEFT): /* word skip left */ if(ods.p_ind > 0) /* Scoot one char left if possible */ ods.p_ind--; @@ -3362,6 +3371,9 @@ display_delimiter(int state) { UCS *bufp, *buf; + if (sendnow) + return; + if(ComposerTopLine - 1 >= BOTTOM()) /* silently forget it */ return; @@ -3418,6 +3430,9 @@ InvertPrompt(int entry, int state) UCS *end; int i; + if (sendnow) + return(TRUE); + buf = utf8_to_ucs4_cpystr(headents[entry].prompt); /* fresh prompt paint */ if(!buf) return(-1); @@ -4373,6 +4388,9 @@ is_blank(int row, int col, int n) void ShowPrompt(void) { + if (sendnow) + return; + if(headents[ods.cur_e].key_label){ menu_header[TO_KEY].name = "^T"; menu_header[TO_KEY].label = headents[ods.cur_e].key_label; diff --git a/pico/display.c b/pico/display.c index 2741be3e..6923e156 100644 --- a/pico/display.c +++ b/pico/display.c @@ -387,6 +387,9 @@ update(void) int scroll = 0; CELL c; + if (sendnow) + return; + #if TYPEAH if (typahead()) return; @@ -916,7 +919,7 @@ updateline(int row, /* row on screen */ int nbflag; /* non-blanks to the right flag? */ int cleartoeol = 0; - if(row < 0 || row > term.t_nrow) + if(row < 0 || row > term.t_nrow || sendnow) return; /* set up pointers to virtual and physical lines */ @@ -1285,7 +1288,7 @@ get_cursor(int *row, int *col) void mlerase(void) { - if (term.t_nrow < term.t_mrow) + if (term.t_nrow < term.t_mrow || sendnow) return; movecursor(term.t_nrow - term.t_mrow, 0); @@ -1360,6 +1363,10 @@ mlyesno(UCS *prompt, int dflt) menu_yesno[6].label = N_("Cancel"); menu_yesno[7].name = "N"; menu_yesno[7].label = (dflt == FALSE) ? "[" N_("No") "]" : N_("No"); + if(Pmaster && Pmaster->onctrlc){ + menu_yesno[8].name = "T"; + menu_yesno[8].label = N_("counT"); + } wkeyhelp(menu_yesno); /* paint generic menu */ sgarbk = TRUE; /* mark menu dirty */ if(Pmaster && curwp) @@ -1438,6 +1445,14 @@ mlyesno(UCS *prompt, int dflt) km_popped++; break; } + + case 'T': + case 't': + if(Pmaster && Pmaster->onctrlc){ + pputs_utf8(_("counT"), 1); + rv = COUNT; + break; + } /* else fall through */ default: @@ -1751,6 +1766,11 @@ mlreplyd(UCS *prompt, UCS *buf, int nbuf, int flg, EXTRAKEYS *extras) b = &buf[ucs4_strlen(buf)]; continue; + case (CTRL|'\\'): + if (c = GetAccent()) + goto text; + continue; + case (CTRL|'F') : /* CTRL-F forward a char*/ case KEY_RIGHT : if(*b == '\0') @@ -1760,6 +1780,18 @@ mlreplyd(UCS *prompt, UCS *buf, int nbuf, int flg, EXTRAKEYS *extras) continue; + case (CTRL|'N'): /* Insert pattern */ + if (pat[0] != '\0'){ + ucs4_strncpy(buf+ucs4_strlen(buf), pat, NPAT); + pputs(pat,1); + b = &buf[ucs4_strlen(buf)]; + dline.vused += ucs4_strlen(pat); + changed = TRUE; + } + else + (*term.t_beep)(); + continue; + case (CTRL|'G') : /* CTRL-G help */ if(term.t_mrow == 0 && km_popped == 0){ movecursor(term.t_nrow-2, 0); @@ -1869,7 +1901,7 @@ mlreplyd(UCS *prompt, UCS *buf, int nbuf, int flg, EXTRAKEYS *extras) #endif default : - +text: /* look for match in extra_v */ for(i = 0; i < 12; i++) if(c && c == extra_v[i]){ @@ -1963,7 +1995,7 @@ emlwrite_ucs4(UCS *message, EML *eml) mlerase(); - if(!(message && *message) || term.t_nrow < 2) + if(!(message && *message) || term.t_nrow < 2 || sendnow) return; /* nothing to write or no space to write, bag it */ bufp = message; @@ -2152,8 +2184,9 @@ mlwrite(UCS *fmt, void *arg) } ret = ttcol; - while(ttcol < term.t_ncol) - pputc(' ', 0); + if(sendnow == 0) + while(ttcol < term.t_ncol) + pputc(' ', 0); movecursor(term.t_nrow - term.t_mrow, ret); @@ -2632,6 +2665,8 @@ pputc(UCS c, /* char to write */ { int ind, width, printable_ascii = 0; + if(sendnow) + return; /* * This is necessary but not sufficient to allow us to draw. Note that * ttrow runs from 0 to t_nrow (so total number of rows is t_nrow+1) @@ -2686,6 +2721,8 @@ void pputs(UCS *s, /* string to write */ int a) /* and its attribute */ { + if(sendnow) + return; while (*s != '\0') pputc(*s++, a); } @@ -2696,6 +2733,8 @@ pputs_utf8(char *s, int a) { UCS *ucsstr = NULL; + if(sendnow) + return; if(s && *s){ ucsstr = utf8_to_ucs4_cpystr(s); if(ucsstr){ @@ -2996,6 +3035,9 @@ wkeyhelp(KEYMENU *keymenu) char nbuf[NLINE]; #endif + if(sendnow) + return; + #ifdef _WINDOWS pico_config_menu_items (keymenu); #endif diff --git a/pico/ebind.h b/pico/ebind.h index 4f1687b4..f8cbbbc3 100644 --- a/pico/ebind.h +++ b/pico/ebind.h @@ -61,7 +61,7 @@ KEYTAB keytab[NBINDS] = { #ifdef MOUSE {KEY_MOUSE, mousepress}, #ifndef _WINDOWS - {CTRL|'\\', toggle_xterm_mouse}, + {CTRL|'|', toggle_xterm_mouse}, #endif #endif {CTRL|'A', gotobol}, @@ -100,7 +100,9 @@ KEYTAB keytab[NBINDS] = { {CTRL|KEY_HOME, gotobob}, {CTRL|KEY_END, gotoeob}, {0x7F, backdel}, - {0, NULL} + {CTRL|'\\', pineaccent}, + {0, +NULL} }; @@ -123,7 +125,7 @@ KEYTAB pkeytab[NBINDS] = { #ifdef MOUSE {KEY_MOUSE, mousepress}, #ifndef _WINDOWS - {CTRL|'\\', toggle_xterm_mouse}, + {CTRL|'|', toggle_xterm_mouse}, #endif #endif {CTRL|'A', gotobol}, diff --git a/pico/edef.h b/pico/edef.h index 209a4600..bea0ed1e 100644 --- a/pico/edef.h +++ b/pico/edef.h @@ -32,6 +32,7 @@ /* initialized global definitions */ +int sendnow = 0; /* should we send now */ int fillcol = 72; /* Current fill column */ int userfillcol = -1; /* Fillcol set from cmd line */ UCS pat[NPAT]; /* Search pattern */ @@ -84,6 +85,7 @@ void *input_cs; /* passed to mbtow() via kbseq() */ /* initialized global external declarations */ +extern int sendnow; /* should we send now */ extern int fillcol; /* Fill column */ extern int userfillcol; /* Fillcol set from cmd line */ extern UCS pat[]; /* Search pattern */ diff --git a/pico/efunc.h b/pico/efunc.h index b551dfc7..52b2bcc5 100644 --- a/pico/efunc.h +++ b/pico/efunc.h @@ -54,8 +54,12 @@ extern int forwline(int, int); extern int backline(int, int); extern int gotobop(int, int); extern int gotoeop(int, int); +extern int pineaccent(int, int); +extern unsigned char accent(UCS, UCS); +extern unsigned char GetAccent(void); extern int forwpage(int, int); extern int backpage(int, int); +extern int deltext (int, int); extern int scrollupline(int, int); extern int scrolldownline(int, int); extern int scrollto(int, int); @@ -249,10 +253,16 @@ extern int forwword(int, int); 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 quote_match(char **, LINE *, char *, size_t, int); +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 --git a/pico/fileio.c b/pico/fileio.c index 5cf124c0..2b598e0c 100644 --- a/pico/fileio.c +++ b/pico/fileio.c @@ -95,6 +95,7 @@ ffgetline(UCS buf[], size_t nbuf, size_t *charsreturned, int msg) { size_t i; UCS ucs; + static int shown = 0; if(charsreturned) *charsreturned = 0; @@ -121,8 +122,10 @@ ffgetline(UCS buf[], size_t nbuf, size_t *charsreturned, int msg) if(charsreturned) *charsreturned = nbuf - 1; - if(msg) + if(msg && !shown){ + shown = 1; emlwrite("File has long line", NULL); + } return FIOLNG; } @@ -131,6 +134,7 @@ ffgetline(UCS buf[], size_t nbuf, size_t *charsreturned, int msg) } if(ucs == CCONV_EOF){ + shown = 0; /* warn the next time, again, only once */ if(ferror(g_pico_fio.fp)){ emlwrite("File read error", NULL); if(charsreturned) diff --git a/pico/line.c b/pico/line.c index e5df3670..fe6847d3 100644 --- a/pico/line.c +++ b/pico/line.c @@ -608,14 +608,12 @@ int lisblank(LINE *line) { int n = 0; - UCS qstr[NLINE]; + char qstr[NLINE]; - n = (glo_quote_str - && quote_match(glo_quote_str, line, qstr, NLINE)) - ? ucs4_strlen(qstr) : 0; + n = quote_match(default_qstr(glo_quote_str, 1), line, qstr, NLINE, 1); for(; n < llength(line); n++) - if(!ucs4_isspace(lgetc(line, n).c)) + if(!ISspace(lgetc(line, n).c)) return(FALSE); return(TRUE); diff --git a/pico/main.c b/pico/main.c index ac5bc388..3036b69a 100644 --- a/pico/main.c +++ b/pico/main.c @@ -163,6 +163,7 @@ main(int argc, char *argv[]) char *file_to_edit = NULL; char *display_charmap = NULL, *dc; char *keyboard_charmap = NULL; + int line_information_on = FALSE; int use_system = 0; char *err = NULL; @@ -416,6 +417,12 @@ main(int argc, char *argv[]) emlwrite(_("You may possibly have new mail."), NULL); } + if (c == (CTRL|'\\')){ + c = GetAccent(); + if (!c) + c = NODATA; + } + if(km_popped) switch(c){ case NODATA: @@ -437,14 +444,29 @@ main(int argc, char *argv[]) mlerase(); } - f = FALSE; + f = (c == (CTRL|'J')); n = 1; + if (!line_information_on) + line_information_on = (c == (CTRL|'C')); + else + line_information_on = ((c == KEY_DOWN) || (c == KEY_UP) || + (c == KEY_RIGHT) || (c == KEY_LEFT) || + (c == (CTRL|'V')) || (c == (CTRL|'Y')) || + (c == (CTRL|'D')) || (c == (CTRL|'F')) || + (c == (CTRL|'B')) || (c == (CTRL|'N')) || + (c == (CTRL|'P')) || (c == (CTRL|'A')) || + (c == (CTRL|'E')) || (c == (CTRL|'U'))) + && (c != (CTRL|'C')); #ifdef MOUSE clear_mfunc(mouse_in_content); #endif /* Do it. */ execute(normalize_cmd(c, fkm, 1), f, n); + if (line_information_on){ + c = (CTRL|'C'); + execute(normalize_cmd(c, fkm, 1), f, n); + } } } diff --git a/pico/osdep/color.h b/pico/osdep/color.h index 0dced80c..dce05118 100644 --- a/pico/osdep/color.h +++ b/pico/osdep/color.h @@ -33,6 +33,10 @@ void pico_endcolor(void); void pico_toggle_color(int); void pico_set_nfg_color(void); void pico_set_nbg_color(void); +char **default_qstr(void *, int); +void add_allowed_qstr(void *, int); +void free_allowed_qstr(void); +void record_quote_string (QSTRING_S *); #endif /* PICO_OSDEP_COLOR_INCLUDED */ diff --git a/pico/osdep/getkey.c b/pico/osdep/getkey.c index b55dd092..827b7da0 100644 --- a/pico/osdep/getkey.c +++ b/pico/osdep/getkey.c @@ -131,6 +131,16 @@ GetKey(void) { UCS ch, status, cc; + if(sendnow){ + ch = Pmaster && Pmaster->auto_cmds && *Pmaster->auto_cmds + ? *Pmaster->auto_cmds++ : NODATA; + + if (ch >= 0x00 && ch <= 0x1F) + ch = CTRL | (ch+'@'); + + return(ch); + } + if(!ReadyForKey(FUDGE-5)) return(NODATA); diff --git a/pico/osdep/terminal.c b/pico/osdep/terminal.c index 72206c01..eb24d90e 100644 --- a/pico/osdep/terminal.c +++ b/pico/osdep/terminal.c @@ -26,6 +26,7 @@ static char rcsid[] = "$Id: terminal.c 921 2008-01-31 02:09:25Z hubert@u.washing #include "../keydefs.h" #include "../pico.h" #include "../mode.h" +#include "../edef.h" #include "raw.h" #include "color.h" @@ -478,6 +479,12 @@ tinfoopen(void) { int row, col; + if (sendnow){ + term.t_nrow = 23; + term.t_ncol = 80; + return 0; + } + /* * determine the terminal's communication speed and decide * if we need to do optimization ... @@ -1253,6 +1260,12 @@ tcapopen(void) { int row, col; + if (sendnow){ + term.t_nrow = 23; + term.t_ncol = 80; + return 0; + } + /* * determine the terminal's communication speed and decide * if we need to do optimization ... diff --git a/pico/pico.c b/pico/pico.c index 166a3d3d..0a47d7f9 100644 --- a/pico/pico.c +++ b/pico/pico.c @@ -138,6 +138,15 @@ pico(PICO *pm) pico_all_done = 0; km_popped = 0; + if (pm->auto_cmds){ + int i; +#define CTRL_X 24 + for (i = 0; pm->auto_cmds[i]; i++); + if ((i > 1) && (pm->auto_cmds[i - 2] == CTRL_X) && + ((pm->auto_cmds[i - 1] == 'y') || (pm->auto_cmds[i-1] == 'Y'))) + sendnow++; + } + if(!vtinit()) /* Init Displays. */ return(COMP_CANCEL); @@ -638,12 +647,19 @@ abort_composer(int f, int n) result = ""; Pmaster->arm_winch_cleanup++; + Pmaster->onctrlc++; if(Pmaster->canceltest){ if(((Pmaster->pine_flags & MDHDRONLY) && !any_header_changes()) || (result = (*Pmaster->canceltest)(redraw_pico_for_callback))){ - pico_all_done = COMP_CANCEL; emlwrite(result, NULL); Pmaster->arm_winch_cleanup--; + if(Pmaster->curpos[0]){ + curwp->w_flag |= WFMODE; /* and modeline so we */ + sgarbk = TRUE; /* redraw the keymenu */ + pclear(term.t_nrow - 1, term.t_nrow + 1); + return(FALSE); + } + pico_all_done = COMP_CANCEL; return(TRUE); } else{ @@ -672,6 +688,12 @@ abort_composer(int f, int n) emlwrite(_("\007Cancel Cancelled"), NULL); break; + case COUNT: + showcpos(1,0); + emlwrite(Pmaster->curpos, NULL); + Pmaster->onctrlc--; + break; + default: mlerase(); } @@ -714,6 +736,19 @@ wquit(int f, int n) return(FALSE); } + /* When we send a message using the command line we are going to + ignore if the user wants to spell check, we assume he already + did */ + if (sendnow){ + ret = (*Pmaster->exittest)(Pmaster->headents, + redraw_pico_for_callback, + Pmaster->allow_flowed_text, + &result); + if (!ret) + pico_all_done = COMP_EXIT; + return(result ? FALSE : TRUE); + } + #ifdef SPELLER if(Pmaster->always_spell_check) if(spell(0, 0) == -1) diff --git a/pico/pico.h b/pico/pico.h index cf25abea..51bc26ff 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -199,11 +199,13 @@ typedef struct pico_struct { PCOLORS *colors; /* colors for titlebar and keymenu */ void *input_cs; /* passed to mbtow() via kbseq() */ long pine_flags; /* entry mode flags */ + char curpos[80]; /* where are we now? */ /* The next few bits are features that don't fit in pine_flags */ /* If we had this to do over, it would probably be one giant bitmap */ unsigned always_spell_check:1; /* always spell-checking upon quit */ unsigned strip_ws_before_send:1; /* don't default strip bc of flowed */ unsigned allow_flowed_text:1; /* clean text when done to keep flowed */ + unsigned onctrlc; /* are we on ctrl-c command? */ int (*helper)(); /* Pine's help function */ int (*showmsg)(); /* Pine's display_message */ UCS (*suspend)(); /* Pine's suspend */ @@ -222,6 +224,7 @@ typedef struct pico_struct { void (*winch_cleanup)(); /* callback handling screen resize */ void (*newthread)(); /* callback to create new thread */ int arm_winch_cleanup; /* do the winch_cleanup if resized */ + int *auto_cmds; /* Initial keystroke commands */ HELP_T search_help; HELP_T ins_help; HELP_T ins_m_help; diff --git a/pico/random.c b/pico/random.c index 780c083e..4b52bcac 100644 --- a/pico/random.c +++ b/pico/random.c @@ -74,7 +74,10 @@ showcpos(int f, int n) thisline+1, lines+1, (int)((100L*(thisline+1))/(lines+1)), nbc, nch, (nch) ? (int)((100L*nbc)/nch) : 0); - emlwrite(buffer, NULL); + if(Pmaster) + strcpy(Pmaster->curpos, buffer); + else + emlwrite(buffer, NULL); return (TRUE); } diff --git a/pico/search.c b/pico/search.c index 0886b24c..70829082 100644 --- a/pico/search.c +++ b/pico/search.c @@ -36,7 +36,7 @@ int srpat(char *, UCS *, size_t, int); int readpattern(char *, int); int replace_pat(UCS *, int *); int replace_all(UCS *, UCS *); - +int deletepara(int, int); #define FWS_RETURN(RV) { \ thisflag |= CFSRCH; \ @@ -76,6 +76,10 @@ N_(" brackets. This string is the default search prompt."), N_("~ Hitting only ~R~e~t~u~r~n or at the prompt will cause the"), N_(" search to be made with the default value."), " ", +N_("~ Hitting ~^~N will reinsert the last string you searched for"), +N_(" so that you can edit it (in case you made a mistake entering the"), +N_(" search pattern the first time)."), +" ", N_(" The text search is not case sensitive, and will examine the"), N_(" entire message."), " ", @@ -232,10 +236,19 @@ forwsearch(int f, int n) 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; + case (CTRL|'X'): + deltext(f,n); + FWS_RETURN(TRUE); + default: if(status == ABORT) emlwrite(_("Search Cancelled"), NULL); @@ -274,7 +287,7 @@ forwsearch(int f, int n) } if(status + curwp->w_doto >= llength(curwp->w_dotp) || - !eq(defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c)) + !eq((unsigned char)defpat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c)) break; /* do nothing! */ status++; } @@ -600,7 +613,7 @@ srpat(char *utf8prompt, UCS *defpat, size_t defpatlen, int repl_mode) UCS *b; UCS prompt[NPMT]; UCS *promptp; - EXTRAKEYS menu_pat[8]; + EXTRAKEYS menu_pat[10]; menu_pat[i = 0].name = "^Y"; menu_pat[i].label = N_("FirstLine"); @@ -618,6 +631,11 @@ srpat(char *utf8prompt, UCS *defpat, size_t defpatlen, int repl_mode) KS_OSDATASET(&menu_pat[i], KS_NONE); if(!repl_mode){ + menu_pat[++i].name = "^X"; + menu_pat[i].label = N_("DelEnd"); + menu_pat[i].key = (CTRL|'X'); + KS_OSDATASET(&menu_pat[i], KS_NONE); + menu_pat[++i].name = "^T"; menu_pat[i].label = N_("LineNumber"); menu_pat[i].key = (CTRL|'T'); @@ -634,6 +652,11 @@ srpat(char *utf8prompt, UCS *defpat, size_t defpatlen, int repl_mode) 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 @@ -769,7 +792,7 @@ readpattern(char *utf8prompt, int text_mode) UCS *b; UCS tpat[NPAT+20]; UCS *tpatp; - EXTRAKEYS menu_pat[7]; + EXTRAKEYS menu_pat[9]; menu_pat[i = 0].name = "^Y"; menu_pat[i].label = N_("FirstLine"); @@ -782,6 +805,11 @@ readpattern(char *utf8prompt, int text_mode) KS_OSDATASET(&menu_pat[i], KS_NONE); if(text_mode){ + menu_pat[++i].name = "^X"; + menu_pat[i].label = N_("DelEnd"); + menu_pat[i].key = (CTRL|'X'); + KS_OSDATASET(&menu_pat[i], KS_NONE); + menu_pat[++i].name = "^T"; menu_pat[i].label = N_("LineNumber"); menu_pat[i].key = (CTRL|'T'); @@ -797,6 +825,11 @@ readpattern(char *utf8prompt, int text_mode) 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'); @@ -927,7 +960,7 @@ forscan(int *wrapt, /* boolean indicating search wrapped */ c = lgetc(curline, curoff++).c; /* get the char */ /* test it against first char in pattern */ - if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/ + if (eq(c, (unsigned char)patrn[0]) != FALSE) { /* if we find it..*/ /* setup match pointers */ matchline = curline; matchoff = curoff; @@ -948,7 +981,7 @@ forscan(int *wrapt, /* boolean indicating search wrapped */ return(FALSE); /* and test it against the pattern */ - if (eq(*patptr, c) == FALSE) + if (eq((unsigned char) *patptr, c) == FALSE) goto fail; } @@ -1035,3 +1068,25 @@ chword(UCS *wb, UCS *cb) 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 --git a/pico/word.c b/pico/word.c index 145fc1d1..62fa84ea 100644 --- a/pico/word.c +++ b/pico/word.c @@ -25,10 +25,10 @@ static char rcsid[] = "$Id: word.c 769 2007-10-24 00:15:40Z hubert@u.washington. */ #include "headers.h" - +#include "../pith/osdep/color.h" int fpnewline(UCS *quote); -int fillregion(UCS *qstr, REGION *addedregion); +int fillregion(UCS *qstr, UCS *istr, REGION *addedregion); int setquotelevelinregion(int quotelevel, REGION *addedregion); int is_user_separator(UCS c); @@ -431,42 +431,156 @@ is_user_separator(UCS c) 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); + +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 + * rqstr is a pointer to raw qstring; buf points to processed qstring */ int -quote_match(UCS *q, LINE *l, UCS *buf, size_t buflen) +quote_match(char **q, LINE *l, char *buf, size_t buflen, int raw) { - 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++; + QSTRING_S *qs; + char rqstr[NSTRING]; + + qs = qs_quote_match(q, l, rqstr, NSTRING); + if(qs) + record_quote_string(qs); + flatten_qstring(qs, buf, buflen); + if (qs) free_qs(&qs); + + if(raw){ + strncpy(buf, rqstr, buflen < NSTRING ? buflen : NSTRING); + buf[buflen-1] = '\0'; } - return(n); /* never reached */ + + 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 @@ -721,6 +835,7 @@ fillpara(int f, int n) } if(action == 'R' && curwp->w_markp){ + char qstrfl[NSTRING]; /* let yank() know that it may be restoring a paragraph */ thisflag |= CFFILL; @@ -733,21 +848,25 @@ fillpara(int f, int n) /* 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; - + && quote_match(default_qstr(glo_quote_str, 1), + (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, &addedregion)) + 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. @@ -759,17 +878,16 @@ fillpara(int f, int n) 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); + istr = indent_match(default_qstr(glo_quote_str, 1), curwp->w_dotp, ind_str, NSTRING, 0) + && *ind_str ? utf8_to_ucs4_cpystr(ind_str) : NULL; + qstr = (quote_match(default_qstr(glo_quote_str, 1), 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); @@ -783,9 +901,15 @@ fillpara(int f, int n) /* * Fillregion moves dot to the end of the filled region. */ - if(!fillregion(qstr, &addedregion)) + 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 */ @@ -827,16 +951,16 @@ fillpara(int f, int n) * can delete it and restore the saved part. */ int -fillregion(UCS *qstr, REGION *addedregion) +fillregion(UCS *qstr, UCS *istr, REGION *addedregion) { long c, sz, last_char = 0; - int i, j, qlen, same_word, + 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]; + UCS line_last, word[NSTRING], quoid[NSTRING], qstr2[NSTRING]; REGION region; /* if region starts midline insert a newline */ @@ -847,6 +971,35 @@ fillregion(UCS *qstr, REGION *addedregion) 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'; + qstr = qstr2; + } + /* cut the paragraph into our fill buffer */ fdelete(); if(!getregion(®ion, curwp->w_markp, curwp->w_marko)) @@ -863,28 +1016,36 @@ fillregion(UCS *qstr, REGION *addedregion) /* 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++]); - } + if(qstr || istr){ + for(i = 0; quoid[i] != '\0' ; i++) + 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 = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){ + else{ + if(qstr || istr){ + for (i = 0; (c = fremove(i)) != '\0'; i++){ + word[i] = c; + word[i+1] = '\0'; + if(ucs4_strlenis(word) >= ucs4_strlenis(quoid)) + break; + } + i++; + } + else + i = 0; + for(; ISspace(c = fremove(i)); i++){ linsert(1, line_last = (UCS) c); line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1); } + } /* then digest the rest... */ while((c = fremove(i++)) >= 0){ @@ -905,21 +1066,22 @@ fillregion(UCS *qstr, REGION *addedregion) case TAB : case ' ' : + case NBSP: spaces++; break; default : if(spaces){ /* flush word? */ - if((line_len - qlen > 0) + if((line_len - qlenis > 0) && line_len + word_len + 1 > fillcol - && ((ucs4_isspace(line_last)) + && ((ISspace(line_last)) || (linsert(1, ' '))) && same_word == 0 && (line_len = fpnewline(qstr))) line_last = ' '; /* no word-flush space! */ if(word_len){ /* word to write? */ - if(line_len && !ucs4_isspace(line_last)){ + if(line_len && !ISspace(line_last)){ linsert(1, ' '); /* need padding? */ line_len++; } @@ -941,8 +1103,8 @@ fillregion(UCS *qstr, REGION *addedregion) if(word_ind + 1 >= NSTRING){ /* Magic! Fake that we output a wrapped word */ - if((line_len - qlen > 0) && same_word == 0){ - if(!ucs4_isspace(line_last)) + if((line_len - qlenis > 0) && same_word == 0){ + if(!ISspace(line_last)) linsert(1, ' '); line_len = fpnewline(qstr); } @@ -964,12 +1126,12 @@ fillregion(UCS *qstr, REGION *addedregion) } if(word_len){ - if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol) && same_word == 0){ - if(!ucs4_isspace(line_last)) + if((line_len - qlenis > 0) && (line_len + word_len + 1 > fillcol) && same_word == 0){ + if(!ISspace(line_last)) linsert(1, ' '); (void) fpnewline(qstr); } - else if(line_len && !ucs4_isspace(line_last)) + else if(line_len && !ISspace(line_last)) linsert(1, ' '); for(j = 0; j < word_ind; j++) @@ -1027,11 +1189,11 @@ fpnewline(UCS *quote) int len; lnewline(); - for(len = 0; quote && *quote; quote++){ + for(len = ucs4_strlenis(quote); quote && *quote; quote++){ int ww; - ww = wcellwidth(*quote); - len += (ww >= 0 ? ww : 1); +/* ww = wcellwidth(*quote); + len += (ww >= 0 ? ww : 1);*/ linsert(1, *quote); } @@ -1175,5 +1337,45 @@ setquotelevelinregion(int quotelevel, REGION *addedregion) 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); +} + |