/* * Insert a newline. Bound to "C-M". */ int newline(int f, int n) { register int s; if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ if (n < 0) return (FALSE); if(TERM_OPTIMIZE && (curwp->w_dotp != curwp->w_bufp->b_linep)){ int l; if(worthit(&l)){ if(curwp->w_doto != 0) l++; scrolldown(curwp, l, n); } } /* if we are in C mode and this is a default <NL> */ /* pico's never in C mode */ if(Pmaster && Pmaster->allow_flowed_text && curwp->w_doto && ucs4_isspace(lgetc(curwp->w_dotp, curwp->w_doto - 1).c) && !(curwp->w_doto == 3 && lgetc(curwp->w_dotp, 0).c == '-' && lgetc(curwp->w_dotp, 1).c == '-' && lgetc(curwp->w_dotp, 2).c == ' ')){ /* * flowed mode, make the newline a hard one by * stripping trailing space. */ int i, dellen; for(i = curwp->w_doto - 1; i && ucs4_isspace(lgetc(curwp->w_dotp, i - 1).c); i--); dellen = curwp->w_doto - i; curwp->w_doto = i; ldelete(dellen, NULL); } /* insert some lines */ while (n--) { if ((s=lnewline()) != TRUE) return (s); } return (TRUE); }
/* * Tell the caller if the given line is blank or not. */ int lisblank(LINE *line) { int n = 0; UCS qstr[NLINE]; n = (glo_quote_str && quote_match(glo_quote_str, line, qstr, NLINE)) ? ucs4_strlen(qstr) : 0; for(; n < llength(line); n++) if(!ucs4_isspace(lgetc(line, n).c)) return(FALSE); return(TRUE); }
int isquotedspace(LINE *line) { int i, was_quote = 0; for(i = 0; i < llength(line); i++){ if(lgetc(line, i).c == '>') was_quote = 1; else if(was_quote && lgetc(line, i).c == ' '){ if(i+1 < llength(line) && ucs4_isspace(lgetc(line,i+1).c)) return 1; else return 0; } else return 0; } return 0; }
/* * breplace - replace the current window's text with the given * LINEs */ void breplace(void *w) { register LINE *lp; register LINE *fp; fp = lforw(curbp->b_linep); while((lp = fp) != curbp->b_linep){ /* blast old lines */ fp = lforw(lp); free(lp); } free(curbp->b_linep); curbp->b_linep = PT(w)->linep; /* arrange pointers */ /* * Undo space-stuffing that was done when we were preparing to send. * Some error happened so we're back to the composer. */ if(Pmaster && Pmaster->space_stuffed){ Pmaster->space_stuffed = 0; for(lp = lforw(curbp->b_linep); lp != curbp->b_linep; lp = lforw(lp)){ if(llength(lp) && ucs4_isspace(lgetc(lp, 0).c)){ curwp->w_dotp = lp; curwp->w_doto = 0; forwdel(FALSE,1); } } } curwp->w_linep = lforw(curbp->b_linep); curwp->w_dotp = lforw(curbp->b_linep); curwp->w_doto = 0; curwp->w_markp = curwp->w_imarkp = NULL; curwp->w_marko = curwp->w_imarko = 0; curbp->b_dotp = curwp->w_dotp; curbp->b_doto = curbp->b_marko = 0; curbp->b_markp = NULL; curbp->b_linecnt = -1; curwp->w_flag |= WFHARD; }
/* * Remove all trailing white space from the text */ int stripwhitespace(void) { int i; LINE *cur_line = lforw(curbp->b_linep); do{ /* we gotta test for the sigdash case here */ if(!(cur_line->l_used == 3 && lgetc(cur_line, 0).c == '-' && lgetc(cur_line, 1).c == '-' && lgetc(cur_line, 2).c == ' ')) for(i = cur_line->l_used - 1; i >= 0; i--) if(ucs4_isspace(lgetc(cur_line, i).c)) cur_line->l_used--; else break; }while((cur_line = lforw(cur_line)) != curbp->b_linep); return 0; }
/* * The region we're filling is the region from dot to mark. * We cut out that region and then put it back in filled. * The cut out part is saved in the ldelete call and the * reinstalled region is noted in addedregion, so that yank() * can delete it and restore the saved part. */ int fillregion(UCS *qstr, REGION *addedregion) { long c, sz, last_char = 0; int i, j, qlen, same_word, spaces, word_len, word_ind, line_len, ww; int starts_midline = 0; int ends_midline = 0; int offset_into_start; LINE *line_before_start, *lp; UCS line_last, word[NSTRING]; REGION region; /* if region starts midline insert a newline */ if(curwp->w_doto > 0 && curwp->w_doto < llength(curwp->w_dotp)) starts_midline++; /* if region ends midline insert a newline at end */ if(curwp->w_marko > 0 && curwp->w_marko < llength(curwp->w_markp)) ends_midline++; /* cut the paragraph into our fill buffer */ fdelete(); if(!getregion(®ion, curwp->w_markp, curwp->w_marko)) return(FALSE); if(!ldelete(region.r_size, finsert)) return(FALSE); line_before_start = lback(curwp->w_dotp); offset_into_start = curwp->w_doto; if(starts_midline) lnewline(); /* Now insert it back wrapped */ spaces = word_len = word_ind = line_len = same_word = 0; qlen = qstr ? ucs4_strlen(qstr) : 0; /* Beginning with leading quoting... */ if(qstr){ i = 0; while(qstr[i]){ ww = wcellwidth(qstr[i]); line_len += (ww >= 0 ? ww : 1); linsert(1, qstr[i++]); } line_last = ' '; /* no word-flush space! */ } /* remove first leading quotes if any */ if(starts_midline) i = 0; else for(i = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){ linsert(1, line_last = (UCS) c); line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1); } /* then digest the rest... */ while((c = fremove(i++)) >= 0){ last_char = c; switch(c){ case '\n' : /* skip next quote string */ j = 0; while(j < qlen && ((c = fremove(i+j)) == qstr[j] || c == ' ')) j++; i += j; if(!spaces) spaces++; same_word = 0; break; case TAB : case ' ' : spaces++; same_word = 0; break; default : if(spaces){ /* flush word? */ if((line_len - qlen > 0) && line_len + word_len + 1 > fillcol && ((ucs4_isspace(line_last)) || (linsert(1, ' '))) && (line_len = fpnewline(qstr))) line_last = ' '; /* no word-flush space! */ if(word_len){ /* word to write? */ if(line_len && !ucs4_isspace(line_last)){ linsert(1, ' '); /* need padding? */ line_len++; } line_len += word_len; for(j = 0; j < word_ind; j++) linsert(1, line_last = word[j]); if(spaces > 1 && strchr(".?!:;\")", line_last)){ linsert(2, line_last = ' '); line_len += 2; } word_len = word_ind = 0; } spaces = 0; } if(word_ind + 1 >= NSTRING){ /* Magic! Fake that we output a wrapped word */ if((line_len - qlen > 0) && !same_word++){ if(!ucs4_isspace(line_last)) linsert(1, ' '); line_len = fpnewline(qstr); } line_len += word_len; for(j = 0; j < word_ind; j++) linsert(1, word[j]); word_len = word_ind = 0; line_last = ' '; } word[word_ind++] = (UCS) c; ww = wcellwidth((UCS) c); word_len += (ww >= 0 ? ww : 1); break; } } if(word_len){ if((line_len - qlen > 0) && (line_len + word_len + 1 > fillcol)){ if(!ucs4_isspace(line_last)) linsert(1, ' '); (void) fpnewline(qstr); } else if(line_len && !ucs4_isspace(line_last)) linsert(1, ' '); for(j = 0; j < word_ind; j++) linsert(1, word[j]); } if(last_char == '\n') lnewline(); if(ends_midline) (void) fpnewline(qstr); /* * Calculate the size of the region that was added. */ swapmark(0,1); /* mark current location after adds */ addedregion->r_linep = lforw(line_before_start); addedregion->r_offset = offset_into_start; lp = addedregion->r_linep; sz = llength(lp) - addedregion->r_offset; if(lforw(lp) != curwp->w_markp->l_fp){ lp = lforw(lp); while(lp != curwp->w_markp->l_fp){ sz += llength(lp) + 1; lp = lforw(lp); } } sz -= llength(curwp->w_markp) - curwp->w_marko; addedregion->r_size = sz; swapmark(0,1); if(ends_midline){ /* * We want to back up to the end of the original * region instead of being here after the added newline. */ curwp->w_doto = 0; backchar(0, 1); unmarkbuffer(); markregion(1); } return(TRUE); }
/* Word wrap on n-spaces. Back-over whatever precedes the point on the current * line and stop on the first word-break or the beginning of the line. If we * reach the beginning of the line, jump back to the end of the word and start * a new line. Otherwise, break the line at the word-break, eat it, and jump * back to the end of the word. * Returns TRUE on success, FALSE on errors. */ int wrapword(void) { register int cnt; /* size of word wrapped to next line */ register int bp; /* index to wrap on */ register int first = -1; int wid, ww; if(curwp->w_doto <= 0) /* no line to wrap? */ return(FALSE); wid = 0; for(bp = cnt = 0; cnt < llength(curwp->w_dotp) && !bp; cnt++){ if(ucs4_isspace(lgetc(curwp->w_dotp, cnt).c)){ first = 0; if(lgetc(curwp->w_dotp, cnt).c == TAB){ ++wid; while(wid & 0x07) ++wid; } else ++wid; } else{ ww = wcellwidth((UCS) lgetc(curwp->w_dotp, cnt).c); wid += (ww >= 0 ? ww : 1); if(!first) first = cnt; } if(first > 0 && wid > fillcol) bp = first; } if(!bp) return(FALSE); /* bp now points to the first character of the next line */ cnt = curwp->w_doto - bp; curwp->w_doto = bp; if(!lnewline()) /* break the line */ return(FALSE); /* * if there's a line below, it doesn't start with whitespace * and there's room for this line... */ if(!(curbp->b_flag & BFWRAPOPEN) && lforw(curwp->w_dotp) != curbp->b_linep && llength(lforw(curwp->w_dotp)) && !ucs4_isspace(lgetc(lforw(curwp->w_dotp), 0).c) && (llength(curwp->w_dotp) + llength(lforw(curwp->w_dotp)) < fillcol)){ gotoeol(0, 1); /* then pull text up from below */ if(lgetc(curwp->w_dotp, curwp->w_doto - 1).c != ' ') linsert(1, ' '); forwdel(0, 1); gotobol(0, 1); } curbp->b_flag &= ~BFWRAPOPEN; /* don't open new line next wrap */ /* restore dot (account for NL) */ if(cnt && !forwchar(0, cnt < 0 ? cnt-1 : cnt)) return(FALSE); return(TRUE); }
int ucs4_ispunct(UCS c) { return !ucs4_isalnum(c) && !ucs4_isspace(c); }
/* * This function serves two purposes, 1) to strip white space when * Pmaster asks that the composition have its trailing white space * stripped, or 2) to prepare the text as flowed text, as Pmaster * is telling us that we're working with flowed text. * * What flowed currently means to us is stripping all trailing white * space, except for one space if the following line is a continuation * of the paragraph. Also, we space-stuff all lines beginning * with white-space, and leave siglines alone. */ int cleanwhitespace(void) { LINE *cursor_dotp = NULL, **lp = NULL; int i = 0, cursor_doto = 0, is_cursor_line = 0; int do_space_stuffing = 0; if(Pmaster && Pmaster->allow_flowed_text && !(*Pmaster->user_says_noflow)()) do_space_stuffing++; cursor_dotp = curwp->w_dotp; cursor_doto = curwp->w_doto; gotobob(FALSE, 1); for(lp = &curwp->w_dotp; (*lp) != curbp->b_linep; (*lp) = lforw(*lp)){ if(!(llength(*lp) == 3 && lgetc(*lp, 0).c == '-' && lgetc(*lp, 1).c == '-' && lgetc(*lp, 2).c == ' ') && llength(*lp)){ is_cursor_line = (cursor_dotp == (*lp)); /* trim trailing whitespace, to be added back if flowing */ for(i = llength(*lp); i; i--) if(!ucs4_isspace(lgetc(*lp, i - 1).c)) break; if(i != llength(*lp)){ int flow_line = 0; if(Pmaster && !Pmaster->strip_ws_before_send && lforw(*lp) != curbp->b_linep && llength(lforw(*lp)) && !(ucs4_isspace(lgetc(lforw(*lp), 0).c) || isquotedspace(lforw(*lp))) && !(llength(lforw(*lp)) == 3 && lgetc(lforw(*lp), 0).c == '-' && lgetc(lforw(*lp), 1).c == '-' && lgetc(lforw(*lp), 2).c == ' ')) flow_line = 1; if(flow_line && i && lgetc(*lp, i).c == ' '){ /* flowed line ending with space */ i++; if(i != llength(*lp)){ curwp->w_doto = i; ldelete(llength(*lp) - i, NULL); } } else if(flow_line && i && ucs4_isspace(lgetc(*lp, i).c)){ /* flowed line ending with whitespace other than space*/ curwp->w_doto = i; ldelete(llength(*lp) - i, NULL); linsert(1, ' '); } else{ curwp->w_doto = i; ldelete(llength(*lp) - i, NULL); } } if(do_space_stuffing && llength(*lp) && ucs4_isspace(lgetc(*lp, 0).c)){ /* space-stuff only if flowed */ if(Pmaster) Pmaster->space_stuffed = 1; curwp->w_doto = 0; if(is_cursor_line && cursor_doto) cursor_doto++; linsert(1, ' '); } if(is_cursor_line) cursor_dotp = (*lp); } } /* put the cursor back where we found it */ gotobob(FALSE, 1); curwp->w_dotp = cursor_dotp; curwp->w_doto = (cursor_doto < llength(curwp->w_dotp)) ? cursor_doto : llength(curwp->w_dotp) - 1; return(0); }
/* * This is the general command execution routine. It handles the fake binding * of all the keys to "self-insert". It also clears out the "thisflag" word, * and arranges to move it to the "lastflag", so that the next command can * look at it. Return the status of command. */ int execute(UCS c, int f, int n) { KEYTAB *ktp; int status, ww; ktp = (Pmaster) ? &keytab[0] : &pkeytab[0]; while (ktp->k_fp != NULL) { if (ktp->k_code == c) { if(lastflag&CFFILL){ curwp->w_flag |= WFMODE; if(Pmaster == NULL) sgarbk = TRUE; } thisflag = 0; status = (*ktp->k_fp)(f, n); if((lastflag & CFFILL) && !(thisflag & CFFILL)) fdelete(); if((lastflag & CFFLBF) && !(thisflag & CFFLBF)) kdelete(); lastflag = thisflag; /* * Reset flag saying wrap should open a new line whenever * we execute a command (as opposed to just typing in text). * However, if that command leaves us in the same line on the * screen, then don't reset. */ if(curwp->w_flag & (WFMOVE | WFHARD)) curbp->b_flag |= BFWRAPOPEN; /* wrap should open new line */ return (status); } ++ktp; } if(lastflag & CFFILL) /* blat unusable fill data */ fdelete(); if(lastflag & CFFLBF) kdelete(); if (VALID_KEY(c)) { /* Self inserting. */ if (n <= 0) { /* Fenceposts. */ lastflag = 0; return (n<0 ? FALSE : TRUE); } thisflag = 0; /* For the future. */ /* do the appropriate insertion */ /* pico never does C mode, this is simple */ status = linsert(n, c); /* * Check to make sure we didn't go off of the screen * with that character. Take into account tab expansion. * If so wrap the line... */ if(curwp->w_bufp->b_mode & MDWRAP){ int j, wid; wid = 0; for(j = 0; j < llength(curwp->w_dotp); j++) if(ucs4_isspace(lgetc(curwp->w_dotp, j).c)){ if(lgetc(curwp->w_dotp, j).c == TAB){ ++wid; while(wid & 0x07) ++wid; } else ++wid; } else{ ww = wcellwidth((UCS) lgetc(curwp->w_dotp, j).c); wid += (ww >= 0 ? ww : 1); if(wid > fillcol){ wrapword(); break; } } } lastflag = thisflag; return (status); } unknown_command(c); lastflag = 0; /* Fake last flags. */ return (FALSE); }