summaryrefslogtreecommitdiff
path: root/pico
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
committerEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
commit81e994d7907f850506ddc248f84761a54995e58c (patch)
tree3bc4993b48ddeec45dee51323437200ab975887c /pico
parent077522d7e058133f9de99d0d74481566b21c5a98 (diff)
downloadalpine-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.c378
-rw-r--r--pico/blddate.c8
-rw-r--r--pico/composer.c20
-rw-r--r--pico/display.c54
-rw-r--r--pico/ebind.h8
-rw-r--r--pico/edef.h2
-rw-r--r--pico/efunc.h12
-rw-r--r--pico/fileio.c6
-rw-r--r--pico/line.c8
-rw-r--r--pico/main.c24
-rw-r--r--pico/osdep/color.h4
-rw-r--r--pico/osdep/getkey.c10
-rw-r--r--pico/osdep/terminal.c13
-rw-r--r--pico/pico.c37
-rw-r--r--pico/pico.h3
-rw-r--r--pico/random.c5
-rw-r--r--pico/search.c67
-rw-r--r--pico/word.c334
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(&region, 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);
+}
+