Annotation of sbbs/src/sbbs3/wordwrap.c, revision 1.1.1.1

1.1       root        1: /* $Id: wordwrap.c,v 1.6 2010/05/26 04:54:37 rswindell Exp $ */
                      2: 
                      3: /****************************************************************************
                      4:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      5:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                      6:  *                                                                                                                                                     *
                      7:  * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html         *
                      8:  *                                                                                                                                                     *
                      9:  * This program is free software; you can redistribute it and/or                       *
                     10:  * modify it under the terms of the GNU General Public License                         *
                     11:  * as published by the Free Software Foundation; either version 2                      *
                     12:  * of the License, or (at your option) any later version.                                      *
                     13:  * See the GNU General Public License for more details: gpl.txt or                     *
                     14:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
                     15:  *                                                                                                                                                     *
                     16:  * Anonymous FTP access to the most recent released source is available at     *
                     17:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     18:  *                                                                                                                                                     *
                     19:  * Anonymous CVS access to the development source and modification history     *
                     20:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     21:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     22:  *     (just hit return, no password is necessary)                                                     *
                     23:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     24:  *                                                                                                                                                     *
                     25:  * For Synchronet coding style and modification guidelines, see                                *
                     26:  * http://www.synchro.net/source.html                                                                          *
                     27:  *                                                                                                                                                     *
                     28:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     29:  * format) via e-mail to [email protected]                                                                      *
                     30:  *                                                                                                                                                     *
                     31:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     32:  ****************************************************************************/
                     33: 
                     34: #include <genwrap.h>
                     35: #include <stdlib.h>            /* realloc */
                     36: #include "wordwrap.h"
                     37: 
                     38: static int get_prefix(const char *text, int *bytes, int *len, int maxlen)
                     39: {
                     40:        int             tmp_prefix_bytes,tmp_prefix_len;
                     41:        int             expect;
                     42:        int             depth;
                     43: 
                     44:        *bytes=0;
                     45:        *len=0;
                     46:        tmp_prefix_bytes=0;
                     47:        tmp_prefix_len=0;
                     48:        depth=0;
                     49:        expect=1;
                     50:        if(text[0]!=' ')
                     51:                expect=2;
                     52:        while(expect) {
                     53:                tmp_prefix_bytes++;
                     54:                /* Skip CTRL-A codes */
                     55:                while(text[tmp_prefix_bytes-1]=='\x01') {
                     56:                        tmp_prefix_bytes++;
                     57:                        if(text[tmp_prefix_bytes-1]=='\x01')
                     58:                                break;
                     59:                        tmp_prefix_bytes++;
                     60:                }
                     61:                tmp_prefix_len++;
                     62:                if(text[tmp_prefix_bytes-1]==0 || text[tmp_prefix_bytes-1]=='\n' || text[tmp_prefix_bytes-1]=='\r')
                     63:                        break;
                     64:                switch(expect) {
                     65:                        case 1:         /* At start of possible quote (Next char should be space) */
                     66:                                if(text[tmp_prefix_bytes-1]!=' ')
                     67:                                        expect=0;
                     68:                                else
                     69:                                        expect++;
                     70:                                break;
                     71:                        case 2:         /* At start of nick (next char should be alphanum or '>') */
                     72:                        case 3:         /* At second nick initial (next char should be alphanum or '>') */
                     73:                        case 4:         /* At third nick initial (next char should be alphanum or '>') */
                     74:                                if(text[tmp_prefix_bytes-1]==' ' || text[tmp_prefix_bytes-1]==0)
                     75:                                        expect=0;
                     76:                                else
                     77:                                        if(text[tmp_prefix_bytes-1]=='>')
                     78:                                                expect=6;
                     79:                                        else
                     80:                                                expect++;
                     81:                                break;
                     82:                        case 5:         /* After three regular chars, next HAS to be a '>') */
                     83:                                if(text[tmp_prefix_bytes-1]!='>')
                     84:                                        expect=0;
                     85:                                else
                     86:                                        expect++;
                     87:                                break;
                     88:                        case 6:         /* At '>' next char must be a space */
                     89:                                if(text[tmp_prefix_bytes-1]!=' ')
                     90:                                        expect=0;
                     91:                                else {
                     92:                                        expect=1;
                     93:                                        *len=tmp_prefix_len;
                     94:                                        *bytes=tmp_prefix_bytes;
                     95:                                        depth++;
                     96:                                        /* Some editors don't put double spaces in between */
                     97:                                        if(text[tmp_prefix_bytes]!=' ')
                     98:                                                expect++;
                     99:                                }
                    100:                                break;
                    101:                        default:
                    102:                                expect=0;
                    103:                                break;
                    104:                }
                    105:        }
                    106:        if(*bytes >= maxlen) {
                    107: //             lprintf(LOG_CRIT, "Prefix bytes %u is larger than buffer (%u) here: %*.*s",*bytes,maxlen,maxlen,maxlen,text);
                    108:                *bytes=maxlen-1;
                    109:        }
                    110:        return(depth);
                    111: }
                    112: 
                    113: static void outbuf_append(char **outbuf, char **outp, char *append, int len, int *outlen)
                    114: {
                    115:        char    *p;
                    116: 
                    117:        /* Terminate outbuf */
                    118:        **outp=0;
                    119:        /* Check if there's room */
                    120:        if(*outp - *outbuf + len < *outlen) {
                    121:                memcpy(*outp, append, len);
                    122:                *outp+=len;
                    123:                return;
                    124:        }
                    125:        /* Not enough room, double the size. */
                    126:        *outlen *= 2;
                    127:        p=realloc(*outbuf, *outlen);
                    128:        if(p==NULL) {
                    129:                /* Can't do it. */
                    130:                *outlen/=2;
                    131:                return;
                    132:        }
                    133:        /* Set outp for new buffer */
                    134:        *outp=p+(*outp - *outbuf);
                    135:        *outbuf=p;
                    136:        memcpy(*outp, append, len);
                    137:        *outp+=len;
                    138:        return;
                    139: }
                    140: 
                    141: static int compare_prefix(char *old_prefix, int old_prefix_bytes, const char *new_prefix, int new_prefix_bytes)
                    142: {
                    143:        int i;
                    144: 
                    145:        if(new_prefix_bytes != old_prefix_bytes) {
                    146:                if(new_prefix_bytes < old_prefix_bytes) {
                    147:                        if(memcmp(old_prefix, new_prefix, new_prefix_bytes)!=0)
                    148:                                return(-1);
                    149:                        for(i=new_prefix_bytes; i<old_prefix_bytes; i++) {
                    150:                                if(!isspace((unsigned char)old_prefix[i]))
                    151:                                        return(-1);
                    152:                        }
                    153:                }
                    154:                else {
                    155:                        if(memcmp(old_prefix, new_prefix, old_prefix_bytes)!=0)
                    156:                                return(-1);
                    157:                        for(i=old_prefix_bytes; i<new_prefix_bytes; i++) {
                    158:                                if(!isspace((unsigned char)new_prefix[i]))
                    159:                                        return(-1);
                    160:                        }
                    161:                }
                    162:                return(0);
                    163:        }
                    164:        if(memcmp(old_prefix,new_prefix,new_prefix_bytes)!=0)
                    165:                return(-1);
                    166: 
                    167:        return(0);
                    168: }
                    169: 
                    170: char* wordwrap(char* inbuf, int len, int oldlen, BOOL handle_quotes)
                    171: {
                    172:        int                     l;
                    173:        int                     crcount=0;
                    174:        long            i,k,t;
                    175:        int                     ocol=1;
                    176:        int                     icol=1;
                    177:        char*           outbuf;
                    178:        char*           outp;
                    179:        char*           linebuf;
                    180:        char*           prefix=NULL;
                    181:        int                     prefix_len=0;
                    182:        int                     prefix_bytes=0;
                    183:        int                     quote_count=0;
                    184:        int                     old_prefix_bytes=0;
                    185:        int                     outbuf_size=0;
                    186:        int                     inbuf_len=strlen(inbuf);
                    187: 
                    188:        outbuf_size=inbuf_len*3+1;
                    189:        if((outbuf=(char*)malloc(outbuf_size))==NULL)
                    190:                return NULL;
                    191:        outp=outbuf;
                    192: 
                    193:        if((linebuf=(char*)malloc(inbuf_len+2))==NULL) /* room for ^A codes */
                    194:                return NULL;
                    195: 
                    196:        if(handle_quotes) {
                    197:                if((prefix=(char *)malloc(inbuf_len+1))==NULL) { /* room for ^A codes */
                    198:                        free(linebuf);
                    199:                        return NULL;
                    200:                }
                    201:                prefix[0]=0;
                    202:        }
                    203: 
                    204:        outbuf[0]=0;
                    205:        /* Get prefix from the first line (ouch) */
                    206:        l=0;
                    207:        i=0;
                    208:        if(handle_quotes && (quote_count=get_prefix(inbuf, &prefix_bytes, &prefix_len, len*2+2))!=0) {
                    209:                i+=prefix_bytes;
                    210:                if(prefix_len>len/3*2) {
                    211:                        /* This prefix is insane (more than 2/3rds of the new width) hack it down to size */
                    212:                        /* Since we're hacking it, we will always end up with a hardcr on this line. */
                    213:                        /* ToDo: Something prettier would be nice. */
                    214:                        sprintf(prefix," %d> ",quote_count);
                    215:                        prefix_len=strlen(prefix);
                    216:                        prefix_bytes=strlen(prefix);
                    217:                }
                    218:                else {
                    219:                        memcpy(prefix,inbuf,prefix_bytes);
                    220:                        /* Terminate prefix */
                    221:                        prefix[prefix_bytes]=0;
                    222:                }
                    223:                memcpy(linebuf,prefix,prefix_bytes);
                    224:                l=prefix_bytes;
                    225:                ocol=prefix_len+1;
                    226:                icol=prefix_len+1;
                    227:                old_prefix_bytes=prefix_bytes;
                    228:        }
                    229:        for(; inbuf[i]; i++) {
                    230:                if(l>=len*2+2) {
                    231:                        l-=4;
                    232:                        linebuf[l]=0;
                    233: //                     lprintf(LOG_CRIT, "Word wrap line buffer exceeded... munging line %s",linebuf);
                    234:                }
                    235:                switch(inbuf[i]) {
                    236:                        case '\r':
                    237:                                crcount++;
                    238:                                break;
                    239:                        case '\n':
                    240:                                if(handle_quotes && (quote_count=get_prefix(inbuf+i+1, &prefix_bytes, &prefix_len, len*2+2))!=0) {
                    241:                                        /* Move the input pointer offset to the last char of the prefix */
                    242:                                        i+=prefix_bytes;
                    243:                                }
                    244:                                if(!inbuf[i+1]) {                       /* EOF */
                    245:                                        linebuf[l++]='\r';
                    246:                                        linebuf[l++]='\n';
                    247:                                        outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size);
                    248:                                        l=0;
                    249:                                        ocol=1;
                    250:                                }
                    251:                                /* If there's a new prefix, it is a hardcr */
                    252:                                else if(compare_prefix(prefix, old_prefix_bytes, inbuf+i+1-prefix_bytes, prefix_bytes)!=0) {
                    253:                                        if(prefix_len>len/3*2) {
                    254:                                                /* This prefix is insane (more than 2/3rds of the new width) hack it down to size */
                    255:                                                /* Since we're hacking it, we will always end up with a hardcr on this line. */
                    256:                                                /* ToDo: Something prettier would be nice. */
                    257:                                                sprintf(prefix," %d> ",quote_count);
                    258:                                                prefix_len=strlen(prefix);
                    259:                                                prefix_bytes=strlen(prefix);
                    260:                                        }
                    261:                                        else {
                    262:                                                memcpy(prefix,inbuf+i+1-prefix_bytes,prefix_bytes);
                    263:                                                /* Terminate prefix */
                    264:                                                prefix[prefix_bytes]=0;
                    265:                                        }
                    266:                                        linebuf[l++]='\r';
                    267:                                        linebuf[l++]='\n';
                    268:                                        outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size);
                    269:                                        memcpy(linebuf,prefix,prefix_bytes);
                    270:                                        l=prefix_bytes;
                    271:                                        ocol=prefix_len+1;
                    272:                                        old_prefix_bytes=prefix_bytes;
                    273:                                }
                    274:                                else if(isspace((unsigned char)inbuf[i+1]) && inbuf[i+1] != '\n' && inbuf[i+1] != '\r') {       /* Next line starts with whitespace.  This is a "hard" CR. */
                    275:                                        linebuf[l++]='\r';
                    276:                                        linebuf[l++]='\n';
                    277:                                        outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size);
                    278:                                        l=prefix_bytes;
                    279:                                        ocol=prefix_len+1;
                    280:                                }
                    281:                                else {
                    282:                                        if(icol < oldlen) {                     /* If this line is overly long, It's impossible for the next word to fit */
                    283:                                                /* k will equal the length of the first word on the next line */
                    284:                                                for(k=0; inbuf[i+1+k] && (!isspace((unsigned char)inbuf[i+1+k])); k++);
                    285:                                                if(icol+k+1 < oldlen) { /* The next word would have fit but isn't here.  Must be a hard CR */
                    286:                                                        linebuf[l++]='\r';
                    287:                                                        linebuf[l++]='\n';
                    288:                                                        outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size);
                    289:                                                        if(prefix)
                    290:                                                                memcpy(linebuf,prefix,prefix_bytes);
                    291:                                                        l=prefix_bytes;
                    292:                                                        ocol=prefix_len+1;
                    293:                                                }
                    294:                                                else {          /* Not a hard CR... add space if needed */
                    295:                                                        if(l<1 || !isspace((unsigned char)linebuf[l-1])) {
                    296:                                                                linebuf[l++]=' ';
                    297:                                                                ocol++;
                    298:                                                        }
                    299:                                                }
                    300:                                        }
                    301:                                        else {                  /* Not a hard CR... add space if needed */
                    302:                                                if(l<1 || !isspace((unsigned char)linebuf[l-1])) {
                    303:                                                        linebuf[l++]=' ';
                    304:                                                        ocol++;
                    305:                                                }
                    306:                                        }
                    307:                                }
                    308:                                icol=prefix_len+1;
                    309:                                break;
                    310:                        case '\x1f':    /* Delete... meaningless... strip. */
                    311:                                break;
                    312:                        case '\b':              /* Backspace... handle if possible, but don't go crazy. */
                    313:                                if(l>0) {
                    314:                                        if(l>1 && linebuf[l-2]=='\x01') {
                    315:                                                if(linebuf[l-1]=='\x01') {
                    316:                                                        ocol--;
                    317:                                                        icol--;
                    318:                                                }
                    319:                                                l-=2;
                    320:                                        }
                    321:                                        else {
                    322:                                                l--;
                    323:                                                ocol--;
                    324:                                                icol--;
                    325:                                        }
                    326:                                }
                    327:                                break;
                    328:                        case '\t':              /* TAB */
                    329:                                linebuf[l++]=inbuf[i];
                    330:                                /* Can't ever wrap on whitespace remember. */
                    331:                                icol++;
                    332:                                ocol++;
                    333:                                while(ocol%8)
                    334:                                        ocol++;
                    335:                                while(icol%8)
                    336:                                        icol++;
                    337:                                break;
                    338:                        case '\x01':    /* CTRL-A */
                    339:                                linebuf[l++]=inbuf[i++];
                    340:                                if(inbuf[i]!='\x01') {
                    341:                                        linebuf[l++]=inbuf[i];
                    342:                                        break;
                    343:                                }
                    344:                        default:
                    345:                                linebuf[l++]=inbuf[i];
                    346:                                ocol++;
                    347:                                icol++;
                    348:                                if(ocol>len && !isspace((unsigned char)inbuf[i])) {             /* Need to wrap here */
                    349:                                        /* Find the start of the last word */
                    350:                                        k=l;                                                                    /* Original next char */
                    351:                                        l--;                                                                    /* Move back to the last char */
                    352:                                        while((!isspace((unsigned char)linebuf[l])) && l>0)             /* Move back to the last non-space char */
                    353:                                                l--;
                    354:                                        if(l==0) {              /* Couldn't wrap... must chop. */
                    355:                                                l=k;
                    356:                                                while(l>1 && linebuf[l-2]=='\x01' && linebuf[l-1]!='\x01')
                    357:                                                        l-=2;
                    358:                                                if(l>0 && linebuf[l-1]=='\x01')
                    359:                                                        l--;
                    360:                                                if(l>0)
                    361:                                                        l--;
                    362:                                        }
                    363:                                        t=l+1;                                                                  /* Store start position of next line */
                    364:                                        /* Move to start of whitespace */
                    365:                                        while(l>0 && isspace((unsigned char)linebuf[l]))
                    366:                                                l--;
                    367:                                        outbuf_append(&outbuf, &outp, linebuf, l+1, &outbuf_size);
                    368:                                        outbuf_append(&outbuf, &outp, "\r\n", 2, &outbuf_size);
                    369:                                        /* Move trailing words to start of buffer. */
                    370:                                        l=prefix_bytes;
                    371:                                        if(k-t>0)                                                       /* k-1 is the last char position.  t is the start of the next line position */
                    372:                                                memmove(linebuf+l, linebuf+t, k-t);
                    373:                                        l+=k-t;
                    374:                                        /* Find new ocol */
                    375:                                        for(ocol=prefix_len+1,t=prefix_bytes; t<l; t++) {
                    376:                                                switch(linebuf[t]) {
                    377:                                                        case '\x01':    /* CTRL-A */
                    378:                                                                t++;
                    379:                                                                if(linebuf[t]!='\x01')
                    380:                                                                        break;
                    381:                                                                /* Fall-through */
                    382:                                                        default:
                    383:                                                                ocol++;
                    384:                                                }
                    385:                                        }
                    386:                                }
                    387:                }
                    388:        }
                    389:        /* Trailing bits. */
                    390:        if(l) {
                    391:                linebuf[l++]='\r';
                    392:                linebuf[l++]='\n';
                    393:                outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size);
                    394:        }
                    395:        *outp=0;
                    396:        /* If there were no CRs in the input, strip all CRs */
                    397:        if(!crcount) {
                    398:                for(inbuf=outbuf; *inbuf; inbuf++) {
                    399:                        if(*inbuf=='\r')
                    400:                                memmove(inbuf, inbuf+1, strlen(inbuf));
                    401:                }
                    402:        }
                    403:        free(linebuf);
                    404: 
                    405:        if(prefix)
                    406:                free(prefix);
                    407: 
                    408:        return outbuf;
                    409: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.