#pragma implementation #include virtpos::virtpos(const char *s) { pos = idx = 0; str = s ? s : ""; } /* We don't handle CRs because this requires scanning the entire string * before being able to map position to index. This would be workable * if the higher levels would keep virtpos objects around at least for * the current line. */ // map a screen position to a string index // the screen position of the beginning of the string index is saved in pos int virtpos::mappos(int offset) { if (offset < pos) pos = idx = 0; #if 0 /* this optimization doesn't seem to work! The idea was to keep the pos & idx around to make small movements left and right cheap to compute. */ while (idx > 0 && pos > offset) { switch (str[--idx]) { case '\t': pos = (pos - 1) & ~7; break; default: --pos; } } #endif int inc; while (str[idx] && pos < offset) { switch (str[idx++]) { case '\f': inc = 10; break; case '\t': inc = 8 - (pos & 7); break; case '\b': if (pos) --pos; continue; default: ++pos; continue; } if (pos + inc > offset) return --idx; pos += inc; } return idx; } int virtpos::mapidx(int i) { // this is not actually correct when backspaces are present int offset; for (offset = i; mappos(offset) < i && str[idx]; ++offset) ; return offset; } // display string beginning at virtual line position offset void virtpos::expand(int offset,CHTYPE *buf,int len) { mappos(offset); int i = 0; int max = 0; CHTYPE attr = A_NORMAL; pos = offset; while (str[idx]) { switch (str[idx++]) { case '\f': { const char *p = "[New Page]"; while (*p && i < len) { buf[i++] = *p++ | A_REVERSE; ++pos; } if (i > max) max = i; if (i >= len) break; continue; } case '\t': do { if (i < len) buf[i++] = ' ' | attr; } while (++pos & 7); if (i > max) max = i; if (i >= len) break; continue; case '\b': if (pos) { --pos; --i; } continue; default: if (i >= len) break; unsigned char c = str[idx-1]; if (i < 0) continue; if (i < max) { if ((char)buf[i] == '_') buf[i] = c | attr | A_UNDERLINE; else if (c == '_') buf[i] |= A_UNDERLINE; else if (c != ' ') buf[i] |= A_STANDOUT; } else buf[i] = c | attr; if (++i > max) max = i; ++pos; continue; } break; } while (max < len) buf[max++] = ' ' | attr; }