/* * Return current column. Stop at first non-blank given TRUE argument. */ int getccol(int bflg) { UCS c; int i, col; col = 0; for (i=0; i<curwp->w_doto; ++i) { c = lgetc(curwp->w_dotp, i).c; if (c!=' ' && c!='\t' && bflg) break; if (c == '\t'){ col |= 0x07; ++col; } else if (ISCONTROL(c)){ col += 2; } else{ int ww; ww = wcellwidth(c); col += (ww >= 0 ? ww : 1); } } return(col); }
/* * fpnewline - output a fill paragraph newline mindful of quote string */ int fpnewline(UCS *quote) { int len; lnewline(); for(len = 0; quote && *quote; quote++){ int ww; ww = wcellwidth(*quote); len += (ww >= 0 ? ww : 1); linsert(1, *quote); } return(len); }
/* * ttputc - Write a character to the display. */ int ttputc(UCS ucs) { unsigned char obuf[MAX(MB_LEN_MAX,32)]; int r, i, width = 0, outchars = 0; int ret = 0; if(ucs < 0x80) return(putchar((unsigned char) ucs)); width = wcellwidth(ucs); if(width < 0){ width = 1; obuf[outchars++] = '?'; } else{ /* * Convert the ucs into the multibyte * character that corresponds to the * ucs in the users locale. */ outchars = wtomb((char *) obuf, ucs); if(outchars < 0){ width = 1; obuf[0] = '?'; outchars = 1; } } for(i = 0; i < outchars; i++){ r = putchar(obuf[i]); ret = (ret == EOF) ? EOF : r; } return(ret); }
/* * 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); }
/*---------------------------------------------------------------------- Write a character to the screen, keeping track of cursor position Input: charater to write Result: character output cursor position variables updated ----------------------------------------------------------------------*/ void Writewchar(UCS ucs) { int width; if(ps_global->in_init_seq) return; switch(ucs){ case LINE_FEED : _line = min(_line+1,ps_global->ttyo->screen_rows); _col =0; mswin_move(_line, _col); break; case RETURN : /* move to column 0 */ _col = 0; mswin_move(_line, _col); case BACKSPACE : /* move back a space if not in column 0 */ if(_col > 0) mswin_move(_line, --_col); break; case BELL : /* ring the bell but don't advance _col */ mswin_beep(); /* libpico call */ break; case TAB: /* if a tab, output it */ do mswin_putc(' '); while(((++_col)&0x07) != 0); break; default: /* pass_ctrl_chars is always 1 for Windows */ width = wcellwidth(ucs); if(width < 0){ mswin_putc('?'); _col++; } else if(_col + width > ps_global->ttyo->screen_cols){ int i; i = ps_global->ttyo->screen_cols - _col - 1; while(i-- > 0) mswin_putc(' '); _col = ps_global->ttyo->screen_cols - 1; mswin_move(_line, _col); mswin_putc('>'); _col++; } else{ mswin_putc(ucs); _col += width; } } if(_col >= ps_global->ttyo->screen_cols){ _col = ps_global->ttyo->screen_cols; mswin_move(_line, _col); } return; }
/* * 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); }
/* * pico_writec - write a char into picotext and advance pointers. * Up to calling routines to keep track of total chars * written. * Incoming text (c) is UTF-8 and written chars are UCS-4. * We need to collect up multiple chars to make a single * UCS-4 char, so there needs to be some state between calls. */ int pico_writec(void *w, int c, int flags) { int rv = 0; if(c == '\r') /* ignore CR's */ rv++; /* so fake it */ else if(c == '\n'){ /* insert newlines on LF */ /* * OK, if there are characters on the current line or * dotp is pointing to the delimiter line, insert a newline * No here's the tricky bit; preserve the implicit EOF newline. */ if(lforw(PT(w)->dotp) == PT(w)->linep && PT(w)->dotp != PT(w)->linep){ PT(w)->dotp = PT(w)->linep; PT(w)->doto = 0; } else{ register LINE *lp; if((lp = lalloc(0)) == NULL){ emlwrite("Can't allocate space for more characters",NULL); return(0); } if(PT(w)->dotp == PT(w)->linep){ lforw(lp) = PT(w)->linep; lback(lp) = lback(PT(w)->linep); lforw(lback(lp)) = lback(PT(w)->linep) = lp; } else{ lforw(lp) = lforw(PT(w)->dotp); lback(lp) = PT(w)->dotp; lback(lforw(lp)) = lforw(PT(w)->dotp) = lp; PT(w)->dotp = lp; PT(w)->doto = 0; } } rv++; } else{ if(flags & PICOREADC_NOUCS){ /* * With this flag we're reverting to the old behavior where no * UTF-8 to UCS-4 translation takes place. We assume nothing * about the incoming byte stream. We just write a byte at a * time. So even though it's being stored in PT each * item is really limited to a single octet value. */ rv = geninsert(&PT(w)->dotp, &PT(w)->doto, PT(w)->linep, c, 0, 1, NULL); } else{ static unsigned char cbuf[6]; static unsigned char *cbufp = cbuf; UCS obuf[MAX(MB_LEN_MAX,32)]; int i, outchars = 0; if(cbufp < cbuf+sizeof(cbuf)){ unsigned char *inputp; unsigned long remaining_octets; UCS ucs; *cbufp++ = (unsigned char) c; inputp = cbuf; remaining_octets = (cbufp - cbuf) * sizeof(unsigned char); ucs = (UCS) utf8_get(&inputp, &remaining_octets); switch(ucs){ case U8G_ENDSTRG: /* incomplete character, wait */ case U8G_ENDSTRI: /* incomplete character, wait */ break; default: if(ucs & U8G_ERROR || ucs == UBOGON){ /* * None of these cases is supposed to happen. If it * does happen then the input stream isn't UTF-8 * so something is wrong. Treat each character in the * input buffer as a separate error character and * print a '?' for each. */ for(inputp = cbuf; inputp < cbufp; inputp++) obuf[outchars++] = '?'; cbufp = cbuf; } else{ /* got a character */ if(ucs >= 0x80 && wcellwidth(ucs) < 0){ /* * This happens when we have a UTF-8 character that * we aren't able to print in our locale. For example, * if the locale is setup with the terminal * expecting ISO-8859-1 characters then there are * lots of UTF-8 characters that can't be printed. * Print a '?' instead. This may be the wrong thing to do. What happens if user is just forwarding and doesn't edit. We are going to lose the original value, aren't we? Maybe we do this only when printing to the screen instead. */ obuf[outchars++] = '?'; } else{ /* * A regular ucs character */ obuf[outchars++] = ucs; } /* update the input buffer */ if(inputp >= cbufp) /* this should be the case */ cbufp = cbuf; else{ /* extra chars for some reason? */ unsigned char *q, *newcbufp; newcbufp = (cbufp - inputp) + cbuf; q = cbuf; while(inputp < cbufp) *q++ = *inputp++; cbufp = newcbufp; } } break; } } else{ /* error */ obuf[0] = '?'; outchars = 1; cbufp = cbuf; /* start over */ } /* * Unless we have trouble translating outchars will be * either 1 or 0. It is the UCS-4 character that we converted * the input to. It's an array just so it can hold ? when * there is trouble. */ rv = 1; for(i = 0; rv && i < outchars; i++) if(!geninsert(&PT(w)->dotp, &PT(w)->doto, PT(w)->linep, obuf[i], 0, 1, NULL)) rv = 0; } } /* * Warning, this is no longer number written, because when we have a * multibyte UTF-8 character we won't write anything until we get all * the bytes. */ return((rv) ? 1 : 0); /* return number written */ }