diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c index 5dcdc9a70ea907545970e62afaa6de600276ac1e..6fd4e80e92419eb2bfe38506e9707b695a59a1fb 100644 --- a/src/sbbs3/js_global.c +++ b/src/sbbs3/js_global.c @@ -612,8 +612,11 @@ static JSBool js_word_wrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { int32 l,len=79; - ulong i,k; - int col=1; + int32 oldlen=79; + int32 crcount; + ulong i,k,t; + int ocol=1; + int icol=1; uchar* inbuf; char* outbuf; char* linebuf; @@ -631,54 +634,146 @@ js_word_wrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if(argc>1) JS_ValueToInt32(cx,argv[1],&len); + if(argc>2) + JS_ValueToInt32(cx,argv[2],&oldlen); + if((linebuf=(char*)malloc((len*2)+2))==NULL) /* room for ^A codes */ return(JS_FALSE); outbuf[0]=0; - for(i=l=0;inbuf[i];) { - if(inbuf[i]=='\r' || inbuf[i]==FF) { - strncat(outbuf,linebuf,l); - l=0; - col=1; - } - else if(inbuf[i]=='\t') { - if((col%8)==0) - col++; - col+=(col%8); - } else if(inbuf[i]==CTRL_A && inbuf[i+1]!=0) { - if(l<(len*2)) { - strncpy(linebuf+l,inbuf+i,2); - l+=2; - } - i+=2; - continue; - } else if(inbuf[i]>=' ') - col++; - linebuf[l]=inbuf[i++]; - if(col<=len) { - l++; - continue; - } - /* wrap line here */ - k=l; - while(k && linebuf[k]>' ' && linebuf[k-1]!=CTRL_A) k--; - if(k==0) /* continuous printing chars, no word wrap possible */ - strncat(outbuf,linebuf,l+1); - else { - i-=(l-k); /* rewind to start of next word */ - linebuf[k]=0; - truncsp(linebuf); - strcat(outbuf,linebuf); + for(i=l=0; inbuf[i]; i++) { + switch(inbuf[i]) { + case '\r': + crcount++; + break; + case '\n': + if(!inbuf[i+1]) { /* EOF */ + linebuf[l++]='\r'; + linebuf[l++]='\n'; + strncat(outbuf, linebuf, l); + l=0; + ocol=1; + } + else if(isspace(inbuf[i+1])) { /* Next line starts with whitespace. This is a "hard" CR. */ + linebuf[l++]='\r'; + linebuf[l++]='\n'; + strncat(outbuf, linebuf, l); + l=0; + ocol=1; + } + else { + if(icol < oldlen) { /* If this line is overly long, It's impossible for the next word to fit */ + /* k will equal the length of the first word on the next line */ + for(k=0; inbuf[i+1+k] && (!isspace(inbuf[i+1+k])); k++); + if(icol+k+1 < oldlen) { /* The next word would have fit but isn't here. Must be a hard CR */ + linebuf[l++]='\r'; + linebuf[l++]='\n'; + strncat(outbuf, linebuf, l); + l=0; + ocol=1; + } + else { /* Not a hard CR... add space if needed */ + if(!isspace(linebuf[l-1])) + linebuf[l++]=' '; + } + } + else { /* Not a hard CR... add space if needed */ + if(!isspace(linebuf[l-1])) + linebuf[l++]=' '; + } + } + icol=1; + break; + case '\x1f': /* Delete... meaningless... strip. */ + break; + case '\b': /* Backspace... handle if possible, but don't go crazy. */ + if(l>0) { + if(l>1 && linebuf[l-2]=='\x01') { + if(linebuf[l-1]=='\x01') { + ocol--; + icol--; + } + l-=2; + } + else { + l--; + ocol--; + icol--; + } + } + break; + case '\t': /* TAB */ + linebuf[l++]=inbuf[i]; + /* Can't ever wrap on whitespace remember. */ + icol++; + ocol++; + while(ocol%8) + ocol++; + while(icol%8) + icol++; + break; + case '\x01': /* CTRL-A */ + linebuf[l++]=inbuf[i++]; + if(inbuf[i]!='\x01') { + linebuf[l++]=inbuf[i]; + break; + } + default: + linebuf[l++]=inbuf[i]; + ocol++; + icol++; + if(ocol>len && !isspace(inbuf[i])) { /* Need to wrap here */ + /* Find the start of the last word */ + k=l; /* Original next char */ + l--; /* Move back to the last char */ + while(!isspace(linebuf[l]) && l>0) /* Move back to the last non-space char */ + l--; + if(l==0) { /* Couldn't wrap... must chop. */ + l=k; + while(linebuf[l-2]=='\x01' && linebuf[l-1]!='\x01') + l-=2; + if(linebuf[l-1]=='\x01') + l--; + l--; + } + t=l+1; /* Store start position of next line */ + /* Move to start of whitespace */ + while(l>0 && isspace(l)) + l--; + strncat(outbuf, linebuf, l+1); + strcat(outbuf, "\r\n"); + /* Move trailing words to start of buffer. */ + if(k-t>0) /* k-1 is the last char position. t is the start of the next line position */ + memmove(linebuf, linebuf+t, k-t); + l=k-t; + /* Find new ocol */ + for(ocol=1,t=0; t<l; t++) { + switch(linebuf[t]) { + case '\x01': /* CTRL-A */ + if(linebuf[t+1]!='\x01') + break; + t++; + /* Fall-through */ + default: + ocol++; + } + } + } } - strcat(outbuf,"\r\n"); - /* skip white space (but no more than one LF) for starting of new line */ - while(inbuf[i] && inbuf[i]<=' ' && inbuf[i]!='\n' && inbuf[i]!=CTRL_A) i++; - if(inbuf[i]=='\n') i++; - l=0; - col=1; } - if(l) /* remainder */ + /* Trailing bits. */ + if(l) { + linebuf[l++]='\r'; + linebuf[l++]='\n'; strncat(outbuf,linebuf,l); + } + /* If there were no CRs in the input, strip all CRs */ + if(!crcount) { + for(inbuf=outbuf; *inbuf; inbuf++) { + if(*inbuf=='\r') + memmove(inbuf, inbuf+1, strlen(inbuf)); + } + } js_str = JS_NewStringCopyZ(cx, outbuf); free(outbuf);