Annotation of researchv10no/ncurses/screen/idln.getst.c, revision 1.1.1.1

1.1       root        1: /*     @(#) idln.getst.c: 1.1 10/15/83 (1.19   2/9/83) */
                      2: 
                      3: #include "curses.ext"
                      4: int InputPending;
                      5: 
                      6: struct st {            /* symbol table */
                      7:        int hash;       /* hashed value of line ("text") */
                      8:        char oc, nc;    /* 0, 1, or many: # times this value occurs */
                      9:        short olno;     /* line # of line in "old" array */
                     10: };
                     11: 
                     12: /*
                     13:  * Routines to deal with calculation of how to do ins/del line optimally.
                     14:  * Update the Screen.  Consider using insert and delete line.
                     15:  * Using Heckel's algorithm from April 1978 CACM.
                     16:  *
                     17:  * This algorithm is based on two observations:
                     18:  *  (1) A line that occurs once and only once in each file must be
                     19:  *     the same line (unchanged but possibly moved).
                     20:  *  (2) If i each file immediately adjacent to a "found" line pair
                     21:  *     there are lines identical to each other, these lines must be
                     22:  *     the same line.  Repeated application will "find" sequences
                     23:  *     of unchanged lines.
                     24:  *
                     25:  * We view the old and new screens' hashed values as the old and new "files".
                     26:  * Since crossing match lines cannot be taken advantage of with real insert
                     27:  * and delete line, we ignore those matches - this is the one real disadvantage
                     28:  * of this algorithm.
                     29:  *
                     30:  * first and last are the integer line numbers (first line is 1) of the
                     31:  * portion of the screen to consider.
                     32:  */
                     33: _id_line(first, last)
                     34: register int first, last;
                     35: {
                     36:        register int i, j, k, n;
                     37:        int base, ndel;
                     38:        int idl_offset = 0;     /* number of extra del lines done so far. */
                     39: #ifdef NONSTANDARD
                     40:        static
                     41: #endif NONSTANDARD
                     42:                struct st symtab[256];
                     43:        /*
                     44:         * oa and na represent the old and new files (SP->cur_body and
                     45:         * SP->std_body, respectively.)  If they are > 0 they are
                     46:         * subscripts in each other (e.g. na[4] = 3 means that na[4]
                     47:         * points to oa[3]).  If they are <= 0 their negative is taken
                     48:         * as a symbol table index into the symtab array.
                     49:         */
                     50: #ifdef NONSTANDARD
                     51:        static
                     52: #endif NONSTANDARD
                     53:                short oa[256], na[256];
                     54: 
                     55:        for (i=0; i<256; i++)
                     56:                symtab[i].hash = symtab[i].oc = symtab[i].nc = 0;
                     57: 
                     58: #ifdef DEBUG
                     59:        if(outf) fprintf(outf, "_id_line(%d, %d)\n", first, last);
                     60: #endif
                     61:        /* Pass 1: enter old file into symtab */
                     62:        for (i=first; i<=last; i++) {
                     63:                n = _getst(SP->std_body[i]->hash, symtab);
                     64:                symtab[n].nc++;
                     65:                na[i] = -n;
                     66:        }
                     67: 
                     68: #ifdef LONGDEBUG
                     69:        if(outf) fprintf(outf, "Pass 2\n");
                     70:        if(outf) fprintf(outf, "na[12] = %d\n", na[12]);
                     71: #endif
                     72:        /* Pass 2: enter new into symtab */
                     73:        for (i=first; i<=last; i++) {
                     74:                n = _getst(SP->cur_body[i]->hash, symtab);
                     75:                symtab[n].oc++;
                     76:                symtab[n].olno = i;
                     77:                oa[i] = -n;
                     78:        }
                     79: 
                     80: #ifdef LONGDEBUG
                     81:        if(outf) fprintf(outf, "Pass 3\n");
                     82:        if(outf) fprintf(outf, "\nsymtab        oc      nc      olno    hash\n");
                     83:        for (i=0; i<256; i++)
                     84:                if (symtab[i].hash)
                     85:                        if(outf) fprintf(outf, "%d      %d      %d      %d      %d\n",
                     86:                                i, symtab[i].oc, symtab[i].nc,
                     87:                                symtab[i].olno, symtab[i].hash);
                     88: #endif
                     89:        /*
                     90:         * Pass 3: Match all lines with exactly one match.
                     91:         * Matching lines in oa and na point at each other.
                     92:         */
                     93:        for (i=first; i<=last; i++) {
                     94:                n = -na[i];
                     95:                if (symtab[n].oc == 1 && symtab[n].nc == 1) {
                     96:                        na[i] = symtab[n].olno;
                     97:                        oa[na[i]] = i;
                     98:                }
                     99:        }
                    100:        oa[first-1] = na[first-1] = first-1;
                    101:        oa[last+1] = na[last+1] = last+1;
                    102: 
                    103:        /* Pass 4: Find following implied matches based on sequence */
                    104: #ifdef DEBUG
                    105:        if(outf) fprintf(outf, "Pass 4\n");
                    106: #endif
                    107:        for (i=first; i<=last; i++) {
                    108:                if (na[i] > 0 && na[i+1] <= 0) {
                    109:                        j = na[i];
                    110:                        if (na[i+1] == oa[j+1]) {
                    111:                                oa[j+1] = i+1;
                    112:                                na[i+1] = j+1;
                    113:                        }
                    114:                }
                    115:        }
                    116: 
                    117:        /* Pass 5: Find preceding implied matches based on sequence */
                    118: #ifdef DEBUG
                    119:        if(outf) fprintf(outf, "Pass 5\n");
                    120:        if(outf) fprintf(outf, "na[12] = %d\n", na[12]);
                    121: #endif
                    122:        for (i=last; i>=first; i--) {
                    123:                if (na[i] > 0 && na[i-1] <= 0) {
                    124:                        j = na[i];
                    125:                        if (na[i-1] == oa[j-1]) {
                    126:                                oa[j-1] = i-1;
                    127:                                na[i-1] = j-1;
                    128:                        }
                    129:                }
                    130:        }
                    131: 
                    132: #ifdef DEBUG
                    133:        if(outf) fprintf(outf, "\ni     oa      na After pass 5\n");
                    134:        for (i=first; i<=last; i++)
                    135:                if(outf) fprintf(outf, "%d      %d      %d\n", i, oa[i], na[i]);
                    136:        if(outf) fprintf(outf, "\n");
                    137: #endif
                    138:        /* Pass 6: Find matches from more than one line, in order.  */
                    139:        for (i=first; i<=last; i++) {
                    140:                if (na[i] < -1 && symtab[-na[i]].nc > 1) {
                    141:                        j = na[i];
                    142: #ifdef DEBUG
                    143:                        if(outf) fprintf(outf, "i %d, na[i] %d\n", i, na[i]);
                    144: #endif
                    145:                        for (k=first; k<last; k++) {
                    146:                                if (j == oa[k]) {
                    147: #ifdef DEBUG
                    148:                        if(outf) fprintf(outf, "k %d, oa[i] %d, matching them up\n", k, oa[i]);
                    149: #endif
                    150:                                        na[i] = k;
                    151:                                        oa[k] = i;
                    152:                                        break;
                    153:                                }
                    154:                        }
                    155:                }
                    156:        }
                    157: #ifdef DEBUG
                    158:        if(outf) fprintf(outf, "\ni     oa      na After pass 6\n");
                    159:        for (i=first; i<=last; i++)
                    160:                if(outf) fprintf(outf, "%d      %d      %d\n", i, oa[i], na[i]);
                    161:        if(outf) fprintf(outf, "\n");
                    162: #endif
                    163: 
                    164:        /*
                    165:         * Passes 7abcd: Remove any match lines that cross backwards.
                    166:         * (Draw lines connecting the matching lines on debug output
                    167:         * to see what I mean about crossing lines.)
                    168:         * The na's must be monotonically increasing except for those < 0
                    169:         * which say there is no match.  k counts the number of matches
                    170:         * we have to throw away.
                    171:         */
                    172:        n = k = 0;      /* k is the added cost to throw away nw-se matches */
                    173:        /* 7a: get nw-se cost in k */
                    174:        for (i=first; i<=last; i++) {
                    175:                if (na[i] > 0 && na[i] < n) {
                    176:                        k += SP->std_body[i]->bodylen;
                    177:                }
                    178:                if (na[i] > n)
                    179:                        n = na[i];
                    180:        }
                    181:        /* 7b: get sw-ne cost in j */
                    182:        /* Consider throwing away in the other direction.  */
                    183:        if (k > 0) {
                    184:                j = 0;  /* j is the added cost to throw away sw-ne matches */
                    185:                n = last+1;
                    186:                for (i=last; i>=first; i--) {
                    187:                        if (na[i] > 0 && na[i] > n) {
                    188:                                j += SP->std_body[i]->bodylen;
                    189:                        }
                    190:                        if (na[i] > 0 && na[i] < n)
                    191:                                n = na[i];
                    192:                }
                    193:        }
                    194:        else
                    195:                j = 1;  /* will be > 0 for sure */
                    196: #ifdef DEBUG
                    197:        if(outf) fprintf(outf, "forward, k is %d, backward, j is %d\n", k, j);
                    198: #endif
                    199: 
                    200:        /* Remove whichever is cheapest. */
                    201:        if (k < j) {
                    202:                /* 7c: remove nw-se */
                    203:                n = 0;
                    204:                for (i=first; i<=last; i++) {
                    205:                        if (na[i] > 0 && na[i] < n) {
                    206:                                oa[na[i]] = -1;
                    207:                                na[i] = -1;
                    208:                        }
                    209:                        if (na[i] > n)
                    210:                                n = na[i];
                    211:                }
                    212:        } else {
                    213:                /* 7d: remove sw-ne */
                    214:                n = last+1;
                    215:                for (i=last; i>=first; i--) {
                    216:                        if (na[i] > 0 && na[i] > n) {
                    217:                                oa[na[i]] = -1;
                    218:                                na[i] = -1;
                    219:                        }
                    220:                        if (na[i] > 0 && na[i] < n)
                    221:                                n = na[i];
                    222:                }
                    223:        }
                    224: #ifdef DEBUG
                    225:        if(outf) fprintf(outf, "\ni     oa      na After pass 7\n");
                    226:        for (i=first; i<=last; i++)
                    227:                if(outf) fprintf(outf, "%d      %d      %d\n", i, oa[i], na[i]);
                    228:        if(outf) fprintf(outf, "\nPass 7\n");
                    229:        if(outf) fprintf(outf, "ILmf %d/32, ILov %d\n",
                    230:                SP->term_costs.ilvar, SP->term_costs.ilfixed);
                    231:        if(outf) fprintf(outf, "i       base    j       k       DC      n\n");
                    232: #endif
                    233: 
                    234:        /*
                    235:         * Pass 8: we go through and remove all matches if the
                    236:         * overall ins/del lines would be too expensive to capatilize on.
                    237:         * j is cost with ins/del line, k is cost without it.  base is the
                    238:         * logical beginning of the oa array, as the array would be after
                    239:         * inserts and deletes, ignoring anything before row i.  This
                    240:         * approximates things by not taking into account SP->curptr motion,
                    241:         * funny insert line costs, or lines that are partially equal.
                    242:         * This macro is the cost to insert or delete n lines at screen line i.
                    243:         * It is approximated for speed and simplicity, but shouldn't be.
                    244:         * The approximation assumes each line is deleted separately.
                    245:         */
                    246: 
                    247: #define idlcost(n, i) n * \
                    248:        (((SP->term_costs.ilvar * (lines-i))>>5) + SP->term_costs.ilfixed)
                    249: 
                    250:        base = ndel = 0;
                    251:        j = k = 0;
                    252:        for (i=first; i<=last; i++) {
                    253: #ifdef DEBUG
                    254:                n = 0;
                    255: #endif
                    256:                if (oa[i] != na[i]) {
                    257:                        /* Cost to turn Phys[i] into Des[i] on same line */
                    258:                        if (SP->cur_body[i] == 0 || SP->cur_body[i]->length == 0) {
                    259:                                k += SP->std_body[i]->bodylen;
                    260:                        } else if (SP->std_body[i] == 0 ||
                    261:                                   SP->std_body[i]->length == 0) {
                    262:                                k += 2; /* guess at cost of clr to eol */
                    263:                        } else {
                    264:                                register chtype *p0, *p1, *p2;
                    265:                                n = SP->cur_body[i]->length -
                    266:                                    SP->std_body[i]->length;
                    267:                                if (n > 0) {
                    268:                                        k += n;
                    269:                                        n = SP->std_body[i]->length;
                    270:                                } else {
                    271:                                        k += -n;
                    272:                                        n = SP->cur_body[i]->length;
                    273:                                }
                    274:                                p0 = &SP->std_body[i]->body[0];
                    275:                                p1 = &SP->std_body[i]->body[n];
                    276:                                p2 = &SP->cur_body[i]->body[n];
                    277:                                while (--p1 >= p0)
                    278:                                        if (*p1 != *--p2)
                    279:                                                k++;
                    280:                        }
                    281:                }
                    282:                /* cost to do using ins/del line */
                    283:                if (na[i] <= 0) {
                    284:                        /* totally different - plan on redrawing whole thing
                    285:                         * (even though chances are good they are partly the
                    286:                         * same - _id_char will take care of this, if it
                    287:                         * happens to get the same line on the screen).
                    288:                         * Should probably figure out what will be there on
                    289:                         * the screen and do above k algorithm on it.
                    290:                         */
                    291:                        j += SP->std_body[i]->bodylen;
                    292:                } else if ((n = (na[i] - base) - i) > 0) {
                    293:                        /* delete line */
                    294:                        j +=  idlcost(n, i);
                    295:                        ndel += n;
                    296:                        base += n;
                    297:                } else if (n < 0) {
                    298:                        /* insert line */
                    299:                        j +=  idlcost((-n), i);
                    300:                        ndel += n;
                    301:                        base += n;
                    302:                }
                    303:                /* else they are the same line: no cost */
                    304: #ifdef DEBUG
                    305:                if(outf) fprintf(outf, "%d      %d      %d      %d      %d", i, base, j, k, SP->std_body[i]->bodylen);
                    306:                if (n < 0)
                    307:                        if(outf) fprintf(outf, "        %d lines inserted", -n);
                    308:                else if (n > 0)
                    309:                        if(outf) fprintf(outf, "        %d lines deleted", n);
                    310:                if(outf) fprintf(outf, "\n");
                    311: #endif
                    312:        }
                    313:        if (j >= k) {
                    314:                /* It's as cheap to just redraw, so do it. */
                    315:                for (i=first; i<=last; i++)
                    316:                        na[i] = oa[i] = -1;
                    317:        } else if (ndel < 0) {
                    318:                ndel = -ndel;
                    319: #ifdef DEBUG
                    320:                if(outf) fprintf(outf, "will do %d extra inserts, so del now.\n", ndel);
                    321: #endif
                    322:                if (SP->des_bot_mgn - last >= 0) {
                    323:                        _pos(last-ndel, 0);
                    324:                        idl_offset += ndel;
                    325:                        _dellines(ndel);
                    326:                }
                    327:        }
                    328: 
                    329: #ifdef DEBUG
                    330:        if(outf) fprintf(outf, "\ni     oa      na After pass 8\n");
                    331:        for (i=first; i<=last; i++)
                    332:                if(outf) fprintf(outf, "%d      %d      %d\n", i, oa[i], na[i]);
                    333:        if(outf) fprintf(outf, "\n");
                    334: #endif
                    335:        /* Pass 9: Do any delete lines that are needed */
                    336:        k = first-1;    /* previous matching spot in oa */
                    337:        ndel = 0;
                    338:        for (i=first; i<=last; i++) {
                    339:                if (oa[i] > 0) {
                    340:                        n = (i-k) - (oa[i]-oa[k]);
                    341: #ifdef DEBUG
                    342:                        if(outf) fprintf(outf,
                    343:                        "del loop, i %d, k %d, oa[i] %d, oa[k] %d, n %d\n",
                    344:                        i, k, oa[i], oa[k], n);
                    345: #endif
                    346:                        if (n > 0) {
                    347:                                if (i-n == SP->des_top_mgn+1) {
                    348:                                        _scrollf(n);
                    349:                                } else {
                    350:                                        _pos(i-n-1, 0);
                    351:                                        _dellines(n);
                    352:                                }
                    353:                                idl_offset += n;
                    354:                                ndel += n;
                    355:                                for (j=i-n; j<=last-n; j++) {
                    356:                                        if (oa[j] > 0 && na[oa[j]] > 0)
                    357:                                                na[oa[j]] -= n;
                    358:                                        _line_free(SP->cur_body[j]);
                    359:                                        SP->cur_body[j] = SP->cur_body[j+n];
                    360:                                        oa[j] = oa[j+n];
                    361:                                }
                    362:                                for ( ; j<=last; j++) {
                    363:                                        if (oa[j] > 0 && na[oa[j]] > 0)
                    364:                                                na[oa[j]] -= n;
                    365:                                        _line_free(SP->cur_body[j]);
                    366:                                        SP->cur_body[j] = NULL;
                    367:                                        oa[j] = -1;
                    368:                                }
                    369:                                i -= n;
                    370:                        }
                    371:                        k = i;
                    372:                }
                    373:        }
                    374: #ifdef DEBUG
                    375:        if(outf) fprintf(outf, "\ni     oa      na After pass 9\n");
                    376:        for (i=first; i<=last; i++)
                    377:                if(outf) fprintf(outf, "%d      %d      %d\n", i, oa[i], na[i]);
                    378:        if(outf) fprintf(outf, "\n");
                    379: #endif
                    380: 
                    381:        /* Half way through - check for typeahead */
                    382:        _chk_typeahead();
                    383:        if (idl_offset == 0 && InputPending) {
                    384: #ifdef DEBUG
                    385:                if (outf) fprintf(outf, "InputPending %d, aborted after dellines\n", InputPending);
                    386: #endif
                    387:                return;
                    388:        }
                    389: 
                    390:        /* for pass 10, j is the next line above i that will be used */
                    391:        for (j=first; na[j] <= 0; j++)
                    392:                ;
                    393:        
                    394:        /* Pass 10: insert and fix remaining lines */
                    395:        for (i=first; i<=last; i++) {
                    396:                if (j <= i)
                    397:                        for (j++; na[j] <= 0; j++)
                    398:                                ;
                    399: #ifdef DEBUG
                    400:                if(outf) fprintf(outf, "i %d, j %d, na[i] %d, na[j] %d\n",
                    401:                        i, j, na[i], na[j]);
                    402:                if (na[i] > 0 && na[i] != i)
                    403:                        if(outf) fprintf(outf, "OOPS: na[%d] is %d\n", i, na[i]);
                    404: #endif
                    405:                /* There are two cases: na[i] < 0  or na[i] == i */
                    406:                if (na[i] < 0) {
                    407:                        /*
                    408:                         * This line must be fixed from scratch.  First
                    409:                         * check to see if the line physically there is
                    410:                         * going to be used later, if so, move it down.
                    411:                         */
                    412:                        if (na[j]==i || ndel+i>last && last<SP->des_bot_mgn+1) {
                    413:                                _pos(i-1, 0);
                    414:                                n = j - i;
                    415:                                idl_offset -= n;
                    416:                                ndel -= n;
                    417:                                _inslines(n);
                    418:                                _chk_typeahead();
                    419:                                if (idl_offset == 0 && InputPending) {
                    420: #ifdef DEBUG
                    421:                                        if (outf) fprintf(outf, "InputPending %d, aborted after dellines\n", InputPending);
                    422: #endif
                    423:                                        return;
                    424:                                }
                    425:                                for (k=last; k>=j; k--) {
                    426:                                        if (na[k] > 0)
                    427:                                                na[k] += n;
                    428:                                        _line_free(SP->cur_body[k]);
                    429:                                        SP->cur_body[k] = SP->cur_body[k-n];
                    430:                                        oa[k] = oa[k-n];
                    431:                                }
                    432:                                for ( ; k>=i; k--) {
                    433:                                        if (na[k] > 0)
                    434:                                                na[k] += n;
                    435:                                        _line_free(SP->cur_body[k]);
                    436:                                        SP->cur_body[k] = NULL;
                    437:                                        oa[k] = 0;
                    438:                                }
                    439:                        }
                    440:                }
                    441:                /* Now transform line i to new line j */
                    442:                if (!InputPending) {
                    443:                        _id_char (SP->cur_body[i], SP->std_body[i], i-1);
                    444:                        if (SP->cur_body[i] != SP->std_body[i])
                    445:                                _line_free (SP->cur_body[i]);
                    446:                        SP->cur_body[i] = SP->std_body[i];
                    447:                }
                    448:        }
                    449: #ifdef DEBUG
                    450:        if(outf) fprintf(outf, "\ni     oa      na After pass 10: _id_line completed\n");
                    451:        for (i=first; i<=last; i++)
                    452:                if(outf) fprintf(outf, "%d      %d      %d\n", i, oa[i], na[i]);
                    453:        if(outf) fprintf(outf, "\n");
                    454: #endif
                    455: }
                    456: 
                    457: int
                    458: _getst(val, symtab)
                    459: register struct st *symtab;
                    460: {
                    461:        register int i;
                    462:        register int h;
                    463:        register int hopcount = 256;
                    464: 
                    465:        i = val & 0377;
                    466:        while ((h=symtab[i].hash) && h != val) {
                    467:                if (++i >= 256)
                    468:                        i = 0;
                    469:                if (--hopcount <= 0) {
                    470:                        _ec_quit("Hash table full in dispcalc", "");
                    471:                }
                    472:        }
                    473:        symtab[i].hash = val;
                    474: #ifdef LONGDEBUG
                    475:        if(outf) fprintf(outf, "_getst, val %d, init slot %d, return %d\n",
                    476:                val, val & 0377, i);
                    477: #endif
                    478:        return i;
                    479: }

unix.superglobalmegacorp.com

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