int vtfilesetsize(VtFile *r, u64int size) { int depth, edepth; VtEntry e; VtBlock *b; assert(ISLOCKED(r)); if(size == 0) return vtfiletruncate(r); if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){ werrstr(ETooBig); return -1; } b = fileload(r, &e); if(b == nil) return -1; /* quick out */ if(e.size == size){ vtblockput(b); return 0; } depth = sizetodepth(size, e.psize, e.dsize); edepth = DEPTH(e.type); if(depth < edepth){ if(shrinkdepth(r, b, &e, depth) < 0){ vtblockput(b); return -1; } }else if(depth > edepth){ if(growdepth(r, b, &e, depth) < 0){ vtblockput(b); return -1; } } if(size < e.size) shrinksize(r, &e, size); e.size = size; vtentrypack(&e, b->data, r->offset % r->epb); vtblockput(b); return 0; }
/* of the final tree. */ void CORD_balance_insert(CORD x, size_t len, ForestElement * forest) { int depth; if (CORD_IS_STRING(x)) { CORD_add_forest(forest, x, len); } else if (IS_CONCATENATION(x) && ((depth = DEPTH(x)) >= MAX_DEPTH || len < min_len[depth])) { struct Concatenation * conc = &(((CordRep *)x) -> concatenation); size_t left_len = LEFT_LEN(conc); CORD_balance_insert(conc -> left, left_len, forest); CORD_balance_insert(conc -> right, len - left_len, forest); } else /* function or balanced */ { CORD_add_forest(forest, x, len); } }
/* * We need cnt more positions on this line. * Open up new space on the screen (this may in fact be a * screen rollup). * * On a dumb terminal we may infact redisplay the rest of the * screen here brute force to keep it pretty. */ void vneedpos(int npcnt) { register int d = DEPTH(vcline); register int rmdr = d * WCOLS - linend; /* * Delete the showmode string on wraparound to last line. Cannot use * vclrech() since the mode string is printed on the echo area, but * not actually a part of it. */ if (value(SHOWMODE) && (value(REDRAW) || (IM && EI)) && npcnt == rmdr - IN && LINE(vcline) + d == WECHO) { int sdc, sdl; char *ocurs; endim(); sdc = destcol, sdl = destline, ocurs = cursor; splitw++; vgoto(WECHO, 0); if (CD) { vputp(CD, 1); } else if (CE) { vputp(CE, 1); } else { int i; for (i = 1; i < WCOLS; i++) vputchar(' '); } destcol = sdc, destline = sdl; cursor = ocurs; splitw = 0; } if (npcnt <= rmdr - IN) return; endim(); vnpins(1); }
/* * Workhorse for rearranging line descriptors on changes. * The idea here is that, starting with line l, cnt lines * have been replaced with newcnt lines. All of these may * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0, * since we may be called from an undo after the screen has * moved a lot. Thus we have to be careful. * * Many boundary conditions here. */ void vreplace(int l, int cnt, int newcnt) { register int from, to, i; bool savenote = 0; #ifdef ADEBUG if (trace) { tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt); tvliny(); } #endif if (l >= vcnt) return; if (l < 0) { if (l + cnt < 0) { /* * Nothing on the screen is relevant. * Settle for redrawing from scratch (later). */ vcnt = 0; return; } /* * Normalize l to top of screen; the add is * really a subtract from cnt since l is negative. */ cnt += l; l = 0; /* * Unseen lines were affect so notify (later). */ savenote++; } /* * These shouldn't happen * but would cause great havoc. */ if (cnt < 0) cnt = 0; if (newcnt < 0) newcnt = 0; /* * Surely worthy of note if more than report * lines were changed. */ if (cnt > value(REPORT) || newcnt > value(REPORT)) savenote++; /* * Same number of lines affeted as on screen, and we * can insert and delete lines. Thus we just type * over them, since otherwise we will push them * slowly off the screen, a clear lose. */ if (cnt == newcnt || vcnt - l == newcnt && AL && DL) { if (cnt > 1 && l + cnt > vcnt) savenote++; vdirty(l, newcnt); } else { /* * Lines are going away, squish them out. */ if (cnt > 0) { /* * If non-displayed lines went away, * always notify. */ if (cnt > 1 && l + cnt > vcnt) savenote++; if (l + cnt >= vcnt) cnt = vcnt - l; else for (from = l + cnt, to = l; from <= vcnt; to++, from++) vlcopy(vlinfo[to], vlinfo[from]); vcnt -= cnt; } /* * Open up space for new lines appearing. * All new lines are piled in the same place, * and will be unpiled by vredraw/vsync, which * inserts lines in front as it unpiles. */ if (newcnt > 0) { /* * Newlines are appearing which may not show, * so notify (this is only approximately correct * when long lines are present). */ if (newcnt > 1 && l + newcnt > vcnt + 1) savenote++; /* * If there will be more lines than fit, then * just throw way the rest of the stuff on the screen. */ if (l + newcnt > WBOT && AL && DL) { vcnt = l; goto skip; } from = vcnt, to = vcnt + newcnt; i = TUBELINES - to; if (i < 0) from += i, to += i; vcnt = to; for (; from >= l; from--, to--) vlcopy(vlinfo[to], vlinfo[from]); for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) { LINE(to) = LINE(from); DEPTH(to) = 0; FLAGS(to) = VDIRT; } } } skip: if (Pline == numbline && cnt != newcnt) /* * When lines positions are shifted, the numbers * will be wrong. */ vdirty(l, WECHO); if (!savenote) notecnt = 0; #ifdef ADEBUG if (trace) tvliny(); #endif }
/* * Fully cleanup the screen, leaving no @ lines except at end when * line after last won't completely fit. The routine vsync is * more conservative and much less work on dumb terminals. */ void vredraw(register int p) { register int l; register line *tp; char temp[LBSIZE]; bool anydl = 0; short oldhold = hold; #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny(); #endif if (holdupd) { holdupd = 3; return; } if (state == HARDOPEN || splitw) return; if (p < 0 /* || p > WECHO */) error(catgets(catd, 1, 221, "Internal error: vredraw")); /* * Trim the ragged edges (lines which are off the screen but * not yet logically discarded), save the current line, and * search for first logical line affected by the redraw. */ vscrap(); CP(temp, linebuf); l = 0; tp = dot - vcline; if (vcnt == 0) LINE(0) = WTOP; while (l < vcnt && LINE(l) < p) l++, tp++; /* * We hold off echo area clearing during the redraw in deference * to a final clear of the echo area at the end if appropriate. */ heldech = 0; hold |= HOLDECH; for (; l < vcnt && Peekkey != ATTN; l++) { if (l == vcline) strcLIN(temp); else getline(*tp); /* * Delete junk between displayed lines. */ if (LINE(l) != LINE(l + 1) && LINE(l) != p) { if (anydl == 0 && DB && CD) { hold = oldhold; vclrech(0); anydl = 1; hold |= HOLDECH; heldech = 0; } vdellin(p, LINE(l) - p, l); } /* * If line image is not know to be up to date, then * redisplay it; else just skip onward. */ LINE(l) = p; if (FLAGS(l) & VDIRT) { DEPTH(l) = vdepth(); if (l != vcline && p + DEPTH(l) - 1 > WBOT) { vscrap(); break; } FLAGS(l) &= ~VDIRT; vreopen(p, lineno(tp), l); p = LINE(l) + DEPTH(l); } else p += DEPTH(l); tp++; } /* * That takes care of lines which were already partially displayed. * Now try to fill the rest of the screen with text. */ if (state == VISUAL && p <= WBOT) { int ovcline = vcline; vcline = l; for (; tp <= dol && Peekkey != ATTN; tp++) { getline(*tp); if (p + vdepth() - 1 > WBOT) break; vopen(tp, p); p += DEPTH(vcline); vcline++; } vcline = ovcline; } /* * Thats all the text we can get on. * Now rest of lines (if any) get either a ~ if they * are past end of file, or an @ if the next line won't fit. */ for (; p <= WBOT && Peekkey != ATTN; p++) vclrlin(p, tp); strcLIN(temp); hold = oldhold; if (heldech) vclrech(0); #ifdef ADEBUG if (trace) tvliny(); #endif }
/* * Open new lines. * * Tricky thing here is slowopen. This causes display updating * to be held off so that 300 baud dumb terminals don't lose badly. * This also suppressed counts, which otherwise say how many blank * space to open up. Counts are also suppressed on intelligent terminals. * Actually counts are obsoleted, since if your terminal is slow * you are better off with slowopen. */ void voOpen ( int c, /* mjm: char --> int */ register int cnt ) { register int ind = 0, i; short oldhold = hold; #ifdef SIGWINCH sigset_t set, oset; #endif if (value(SLOWOPEN) || value(REDRAW) && AL && DL) cnt = 1; #ifdef SIGWINCH sigemptyset(&set); sigaddset(&set, SIGWINCH); sigprocmask(SIG_BLOCK, &set, &oset); #endif vsave(); setLAST(); if (value(AUTOINDENT)) ind = whitecnt(linebuf); if (c == 'O') { vcline--; dot--; if (dot > zero) getDOT(); } if (value(AUTOINDENT)) { #ifdef LISPCODE if (value(LISP)) ind = lindent(dot + 1); #endif } killU(); prepapp(); if (FIXUNDO) vundkind = VMANY; if (state != VISUAL) c = WBOT + 1; else { c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline); if (c < ZERO) c = ZERO; i = LINE(vcline + 1) - c; if (i < cnt && c <= WBOT && (!AL || !DL)) vinslin(c, cnt - i, vcline); } *genindent(ind) = 0; vdoappend(genbuf); vcline++; oldhold = hold; hold |= HOLDROL; vopen(dot, c); hold = oldhold; if (value(SLOWOPEN)) /* * Oh, so lazy! */ vscrap(); else vsync1(LINE(vcline)); cursor = linebuf; linebuf[0] = 0; vappend('o', 1, ind); #ifdef SIGWINCH sigprocmask(SIG_SETMASK, &oset, NULL); #endif }
/* * Now do the insert of the characters (finally). */ void viin(int c) /* int c; /\* mjm: char --> int */ { register cell *tp, *up; register int i, j; register bool noim = 0; int remdoom; short oldhold = hold; hold |= HOLDPUPD; if (tabsize && (IM && EI) && inssiz - doomed > tabslack) /* * There is a tab out there which will be affected * by the insertion since there aren't enough doomed * characters to take up all the insertion and we do * have insert mode capability. */ if (inscol + insmc0 + doomed == tabstart) { /* * The end of the doomed characters sits right at the * start of the tabs, then we don't need to use insert * mode; unless the tab has already been expanded * in which case we MUST use insert mode. */ slakused = 0; noim = !shft; } else { /* * The last really special case to handle is case * where the tab is just sitting there and doesn't * have enough slack to let the insertion take * place without shifting the rest of the line * over. In this case we have to go out and * delete some characters of the tab before we start * or the answer will be wrong, as the rest of the * line will have been shifted. This code means * that terminals with only insert chracter (no * delete character) won't work correctly. */ i = inssiz - doomed - tabslack - slakused; i %= value(TABSTOP); if (i > 0) { vgotoCL(tabstart); godm(); for (i = inssiz - doomed - tabslack; i > 0; i--) vputp(DC, DEPTH(vcline)); enddm(); } } /* * Now put out the characters of the actual insertion. */ vigotoCL(inscol); remdoom = doomed; for (i = inssiz; i > 0; i--) { if (remdoom > insmc1) { remdoom--; endim(); } else if (noim || insmc1 && remdoom == insmc1) endim(); else if (IM && EI) { vcsync(); goim(); } vputchar(c); } if (!IM || !EI || remdoom && remdoom == insmc1) { /* * We are a dumb terminal; brute force update * the rest of the line; this is very much an n^^2 process, * and totally unreasonable at low speed. * * You asked for it, you get it. */ tp = vtube0 + inscol + doomed; for (i = inscol + doomed; i < tabstart; i++) vputchar(*tp++); hold = oldhold; vigotoCL(tabstart + inssiz + insmc0 - doomed); for (i = tabsize - (inssiz - insmc0 - doomed) + shft; i > 0; i--) vputchar(' ' | QUOTE); } else { if (!IN) { /* * On terminals without multi-line * insert in the hardware, we must go fix the segments * between the inserted text and the following * tabs, if they are on different lines. * * Aaargh. */ tp = vtube0; for (j = (inscol + insmc0 + inssiz - 1) / WCOLS + 1; j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) { vgotoCL(j * WCOLS); i = inssiz - doomed + insmc1; up = tp + j * WCOLS - i; goim(); do vputchar(*up++); while (--i && *up); } } else { /* * On terminals with multi line inserts, * life is simpler, just reflect eating of * the slack. */ tp = vtube0 + tabend; for (i = tabsize - (inssiz + insmc1 - doomed); i >= 0; i--) { if ((*--tp & (QUOTE|TRIM)) == QUOTE) { --tabslack; if (tabslack >= slakused) continue; } *tp = ' ' | QUOTE; } } /* * Blank out the shifted positions to be tab positions. */ if (shft) { tp = vtube0 + tabend + shft; for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--) if ((*--tp & QUOTE) == 0) *tp = ' ' | QUOTE; } } /* * Finally, complete the screen image update * to reflect the insertion. */ hold = oldhold; tp = vtube0 + tabstart; up = tp + insmc1 + inssiz - doomed; for (i = tabstart; i > inscol + doomed; i--) *--up = *--tp; #ifdef MB for (i = insmc1; i > 0; i--) *--up = MULTICOL; #endif for (i = inssiz; i > 0; i--) *--up = c | (insmc1 ? MULTICOL : 0); doomed = 0; }
void vappend(int ch, int cnt, int indent) { register int i; register char *gcursor; bool escape; int repcnt; short oldhold = hold; /* * Before a move in hardopen when the line is dirty * or we are in the middle of the printed representation, * we retype the line to the left of the cursor so the * insert looks clean. */ if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) { rubble = 1; wcursor = cursor; vmove(); } vaifirst = indent == 0; /* * Handle replace character by (eventually) * limiting the number of input characters allowed * in the vgetline routine. */ if (ch == 'r') repcnt = 2; else repcnt = 0; /* * If an autoindent is specified, then * generate a mixture of blanks to tabs to implement * it and place the cursor after the indent. * Text read by the vgetline routine will be placed in genbuf, * so the indent is generated there. */ if (value(AUTOINDENT) && indent != 0) { gcursor = genindent(indent); *gcursor = 0; vgotoCL(qcolumn(cursor - 1, genbuf)); } else { gcursor = genbuf; *gcursor = 0; if (ch == 'o') vfixcurs(); } /* * Prepare for undo. Pointers delimit inserted portion of line. */ vUA1 = vUA2 = cursor; /* * If we are not in a repeated command and a ^@ comes in * then this means the previous inserted text. * If there is none or it was too long to be saved, * then beep() and also arrange to undo any damage done * so far (e.g. if we are a change.) */ if ((vglobp && *vglobp == 0) || peekbr()) { if ((INS[0] & (OVERBUF|TRIM)) == OVERBUF) { beep(); if (!splitw) ungetkey('u'); doomed = 0; hold = oldhold; return; } /* * Unread input from INS. * An escape will be generated at end of string. * Hold off n^^2 type update on dumb terminals. */ vglobp = INS; hold |= HOLDQIK; } else if (vglobp == 0) /* * Not a repeated command, get * a new inserted text for repeat. */ INS[0] = 0; /* * For wrapmargin to hack away second space after a '.' * when the first space caused a line break we keep * track that this happened in gobblebl, which says * to gobble up a blank silently. */ gobblebl = 0; /* * Text gathering loop. * New text goes into genbuf starting at gcursor. * cursor preserves place in linebuf where text will eventually go. */ if (*cursor == 0 || state == CRTOPEN) hold |= HOLDROL; for (;;) { if (ch == 'r' && repcnt == 0) escape = 0; else { gcursor = vgetline(repcnt, gcursor, &escape); /* * After an append, stick information * about the ^D's and ^^D's and 0^D's in * the repeated text buffer so repeated * inserts of stuff indented with ^D as backtab's * can work. */ if (HADUP) addtext("^"); else if (HADZERO) addtext("0"); while (CDCNT > 0) addtext("\204"), CDCNT--; if (gobbled) addtext(" "); addtext(ogcursor); } repcnt = 0; /* * Smash the generated and preexisting indents together * and generate one cleanly made out of tabs and spaces * if we are using autoindent. */ if (!vaifirst && value(AUTOINDENT)) { i = fixindent(indent); if (!HADUP) indent = i; gcursor = strend(genbuf); } /* * Limit the repetition count based on maximum * possible line length; do output implied * by further count (> 1) and cons up the new line * in linebuf. */ cnt = vmaxrep(ch, cnt); CP(gcursor + 1, cursor); do { CP(cursor, genbuf); if (cnt > 1) { int oldhold = hold; Outchar = vinschar; hold |= HOLDQIK; ex_printf("%s", genbuf); hold = oldhold; Outchar = vputchar; } cursor += gcursor - genbuf; } while (--cnt > 0); endim(); vUA2 = cursor; if (escape != '\n') CP(cursor, gcursor + 1); /* * If doomed characters remain, clobber them, * and reopen the line to get the display exact. */ if (state != HARDOPEN) { DEPTH(vcline) = 0; if (doomed > 0) { register int cind = cindent(); physdc(cind, cind + doomed); doomed = 0; } i = vreopen(LINE(vcline), lineDOT(), vcline); } /* * All done unless we are continuing on to another line. */ if (escape != '\n') break; /* * Set up for the new line. * First save the current line, then construct a new * first image for the continuation line consisting * of any new autoindent plus the pushed ahead text. */ killU(); addtext(gobblebl ? " " : "\n"); vsave(); cnt = 1; if (value(AUTOINDENT)) { #ifdef LISP if (value(LISP)) indent = lindent(dot + 1); else #endif if (!HADUP && vaifirst) indent = whitecnt(linebuf); vaifirst = 0; strcLIN(vpastwh(gcursor + 1)); gcursor = genindent(indent); *gcursor = 0; if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2]) gcursor = genbuf; CP(gcursor, linebuf); } else { CP(genbuf, gcursor + 1); gcursor = genbuf; } /* * If we started out as a single line operation and are now * turning into a multi-line change, then we had better yank * out dot before it changes so that undo will work * correctly later. */ if (vundkind == VCHNG) { vremote(1, (void (*)(int))yank, 0); undap1--; } /* * Now do the append of the new line in the buffer, * and update the display. If slowopen * we don't do very much. */ vdoappend(genbuf); vundkind = VMANYINS; vcline++; if (state != VISUAL) vshow(dot, NOLINE); else { i += LINE(vcline - 1); vopen(dot, i); if (value(SLOWOPEN)) vscrap(); else vsync1(LINE(vcline)); } strcLIN(gcursor); *gcursor = 0; cursor = linebuf; vgotoCL(qcolumn(cursor - 1, genbuf)); } /* * All done with insertion, position the cursor * and sync the screen. */ hold = oldhold; if (cursor > linebuf) cursor--; if (state != HARDOPEN) vsyncCL(); else if (cursor > linebuf) back1(); doomed = 0; wcursor = cursor; vmove(); }
CORD CORD_cat_char_star(CORD x, const char * y, size_t leny) { size_t result_len; size_t lenx; int depth; if (x == CORD_EMPTY) return(y); if (leny == 0) return(x); if (CORD_IS_STRING(x)) { lenx = strlen(x); result_len = lenx + leny; if (result_len <= SHORT_LIMIT) { char * result = (char *)GC_MALLOC_ATOMIC(result_len + 1); if (result == 0) OUT_OF_MEMORY; # ifdef LINT2 memcpy(result, x, lenx + 1); # else memcpy(result, x, lenx); /* No need to copy the terminating zero */ /* as result[lenx] is written below. */ # endif memcpy(result + lenx, y, leny); result[result_len] = '\0'; return((CORD) result); } else { depth = 1; } } else { CORD right; CORD left; char * new_right; lenx = LEN(x); if (leny <= SHORT_LIMIT/2 && IS_CONCATENATION(x) && CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) { size_t right_len; /* Merge y into right part of x. */ if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) { right_len = lenx - LEN(left); } else if (((CordRep *)x) -> concatenation.left_len != 0) { right_len = lenx - ((CordRep *)x) -> concatenation.left_len; } else { right_len = strlen(right); } result_len = right_len + leny; /* length of new_right */ if (result_len <= SHORT_LIMIT) { new_right = (char *)GC_MALLOC_ATOMIC(result_len + 1); if (new_right == 0) OUT_OF_MEMORY; memcpy(new_right, right, right_len); memcpy(new_right + right_len, y, leny); new_right[result_len] = '\0'; y = new_right; leny = result_len; x = left; lenx -= right_len; /* Now fall through to concatenate the two pieces: */ } if (CORD_IS_STRING(x)) { depth = 1; } else { depth = DEPTH(x) + 1; } } else { depth = DEPTH(x) + 1; } result_len = lenx + leny; } { /* The general case; lenx, result_len is known: */ struct Concatenation * result = GC_NEW(struct Concatenation); if (NULL == result) OUT_OF_MEMORY; result->header = CONCAT_HDR; result->depth = (char)depth; if (lenx <= MAX_LEFT_LEN) result->left_len = (unsigned char)lenx; result->len = (word)result_len; result->left = x; GC_PTR_STORE_AND_DIRTY((void *)&result->right, y); GC_reachable_here(x); if (depth >= MAX_DEPTH) { return(CORD_balance((CORD)result)); } else { return((CORD) result); } } }
/* * Delete display positions stcol through endcol. * Amount of use of special terminal features here is limited. */ void physdc(int stcol, int endcol) { register cell *tp, *up; cell *tpe = NULL; register int i; register int nc = endcol - stcol; #ifdef IDEBUG if (trace) tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol); #endif if (!DC || nc <= 0) return; if (IN) { /* * CONCEPT-100 like terminal. * If there are any ``spaces'' in the material to be * deleted, then this is too hard, just retype. */ vprepins(); up = vtube0 + stcol; i = nc; do { if ((*up++ & (QUOTE|TRIM)) == QUOTE) return; } while (--i); i = 2 * nc; do { if (*up == 0 || (*up++ & QUOTE) == QUOTE) return; } while (--i); vgotoCL(stcol); } else { /* * HP like delete mode. * Compute how much text we are moving over by deleting. * If it appears to be faster to just retype * the line, do nothing and that will be done later. * We are assuming 2 output characters per deleted * characters and that clear to end of line is available. */ i = stcol / WCOLS; if (i != endcol / WCOLS) return; i += LINE(vcline); stcol %= WCOLS; endcol %= WCOLS; up = vtube[i]; tp = up + endcol; tpe = up + WCOLS; while (tp < tpe && *tp) tp++; if (tp - (up + stcol) < 2 * nc) return; vgoto(i, stcol); } /* * Go into delete mode and do the actual delete. * Padding is on DC itself. */ godm(); for (i = nc; i > 0; i--) vputp(DC, DEPTH(vcline)); vputp(ED, 0); /* * Straighten up. * With CONCEPT like terminals, characters are pulled left * from first following null. HP like terminals shift rest of * this (single physical) line rigidly. */ if (IN) { up = vtube0 + stcol; tp = vtube0 + endcol; while (i = *tp++) { if ((i & (QUOTE|TRIM)) == QUOTE) break; *up++ = i; } do *up++ = i; while (--nc); } else { copy(up + stcol, up + endcol, (WCOLS - endcol) * sizeof *up); vclrcell(tpe - nc, nc); } }
CORD CORD_cat_char_star(CORD x, const char * y, size_t leny) { register size_t result_len; register size_t lenx; register int depth; if (x == CORD_EMPTY) return(y); if (leny == 0) return(x); if (CORD_IS_STRING(x)) { lenx = strlen(x); result_len = lenx + leny; if (result_len <= SHORT_LIMIT) { register char * result = MK_GC_MALLOC_ATOMIC(result_len+1); if (result == 0) OUT_OF_MEMORY; memcpy(result, x, lenx); memcpy(result + lenx, y, leny); result[result_len] = '\0'; return((CORD) result); } else { depth = 1; } } else { register CORD right; register CORD left; register char * new_right; register size_t right_len; lenx = LEN(x); if (leny <= SHORT_LIMIT/2 && IS_CONCATENATION(x) && CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) { /* Merge y into right part of x. */ if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) { right_len = lenx - LEN(left); } else if (((CordRep *)x) -> concatenation.left_len != 0) { right_len = lenx - ((CordRep *)x) -> concatenation.left_len; } else { right_len = strlen(right); } result_len = right_len + leny; /* length of new_right */ if (result_len <= SHORT_LIMIT) { new_right = MK_GC_MALLOC_ATOMIC(result_len + 1); if (new_right == 0) OUT_OF_MEMORY; memcpy(new_right, right, right_len); memcpy(new_right + right_len, y, leny); new_right[result_len] = '\0'; y = new_right; leny = result_len; x = left; lenx -= right_len; /* Now fall through to concatenate the two pieces: */ } if (CORD_IS_STRING(x)) { depth = 1; } else { depth = DEPTH(x) + 1; } } else { depth = DEPTH(x) + 1; } result_len = lenx + leny; } { /* The general case; lenx, result_len is known: */ register struct Concatenation * result; result = MK_GC_NEW(struct Concatenation); if (result == 0) OUT_OF_MEMORY; result->header = CONCAT_HDR; result->depth = depth; if (lenx <= MAX_LEFT_LEN) result->left_len = lenx; result->len = result_len; result->left = x; result->right = y; if (depth >= MAX_DEPTH) { return(CORD_balance((CORD)result)); } else { return((CORD) result); } } }
static int shrinksize(VtFile *r, VtEntry *e, uvlong size) { int i, depth, type, isdir, ppb; uvlong ptrsz; uchar score[VtScoreSize]; VtBlock *b; b = vtcacheglobal(r->c, e->score, e->type); if(b == nil) return -1; ptrsz = e->dsize; ppb = e->psize/VtScoreSize; type = e->type; depth = DEPTH(type); for(i=0; i+1<depth; i++) ptrsz *= ppb; isdir = r->dir; while(depth > 0){ if(b->addr == NilBlock){ /* not worth copying the block just so we can zero some of it */ vtblockput(b); return -1; } /* * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes */ /* zero the pointers to unnecessary blocks */ i = (size+ptrsz-1)/ptrsz; for(; i<ppb; i++) memmove(b->data+i*VtScoreSize, vtzeroscore, VtScoreSize); /* recurse (go around again) on the partially necessary block */ i = size/ptrsz; size = size%ptrsz; if(size == 0){ vtblockput(b); return 0; } ptrsz /= ppb; type--; memmove(score, b->data+i*VtScoreSize, VtScoreSize); vtblockput(b); b = vtcacheglobal(r->c, score, type); if(b == nil) return -1; } if(b->addr == NilBlock){ vtblockput(b); return -1; } /* * No one ever truncates BtDir blocks. */ if(depth==0 && !isdir && e->dsize > size) memset(b->data+size, 0, e->dsize-size); vtblockput(b); return 0; }
int vtfileflushbefore(VtFile *r, u64int offset) { VtBlock *b, *bb; VtEntry e; int i, base, depth, ppb, epb, doflush; int index[VtPointerDepth+1], j, ret; VtBlock *bi[VtPointerDepth+2]; uchar *score; assert(ISLOCKED(r)); if(offset == 0) return 0; b = fileload(r, &e); if(b == nil) return -1; /* * compute path through tree for the last written byte and the next one. */ ret = -1; memset(bi, 0, sizeof bi); depth = DEPTH(e.type); bi[depth+1] = b; i = mkindices(&e, (offset-1)/e.dsize, index); if(i < 0) goto Err; if(i > depth) goto Err; ppb = e.psize / VtScoreSize; epb = e.dsize / VtEntrySize; /* * load the blocks along the last written byte */ index[depth] = r->offset % r->epb; for(i=depth; i>=0; i--){ bb = blockwalk(b, index[i], r->c, VtORDWR, &e); if(bb == nil) goto Err; bi[i] = bb; b = bb; } ret = 0; /* * walk up the path from leaf to root, flushing anything that * has been finished. */ base = e.type&~VtTypeDepthMask; for(i=0; i<=depth; i++){ doflush = 0; if(i == 0){ /* leaf: data or dir block */ if(offset%e.dsize == 0) doflush = 1; }else{ /* * interior node: pointer blocks. * specifically, b = bi[i] is a block whose index[i-1]'th entry * points at bi[i-1]. */ b = bi[i]; /* * the index entries up to but not including index[i-1] point at * finished blocks, so flush them for sure. */ for(j=0; j<index[i-1]; j++) if(flushblock(r->c, nil, b->data+j*VtScoreSize, ppb, epb, base+i-1) < 0) goto Err; /* * if index[i-1] is the last entry in the block and is global * (i.e. the kid is flushed), then we can flush this block. */ if(j==ppb-1 && vtglobaltolocal(b->data+j*VtScoreSize)==NilBlock) doflush = 1; } if(doflush){ if(i == depth) score = e.score; else score = bi[i+1]->data+index[i]*VtScoreSize; if(flushblock(r->c, bi[i], score, ppb, epb, base+i) < 0) goto Err; } } Err: /* top: entry. do this always so that the score is up-to-date */ vtentrypack(&e, bi[depth+1]->data, index[depth]); for(i=0; i<nelem(bi); i++) if(bi[i]) vtblockput(bi[i]); return ret; }
OP_ERROR SOP_Ocean::cookMySop(OP_Context &context) { float now = context.getTime(); //std::cout << "cook ocean, t = " << now << std::endl; // lock inputs if (lockInputs(context) >= UT_ERROR_ABORT ) { return error(); } GEO_Point *ppt; UT_Interrupt *boss; // Check to see that there hasn't been a critical error in cooking the SOP. if (error() < UT_ERROR_ABORT) { boss = UTgetInterrupt(); // Start the interrupt server boss->opStart("Updating Ocean"); duplicatePointSource(0,context); int gridres = 1 << int(GRID_RES(now)); float stepsize = GRID_SIZE(now) / (float)gridres; bool do_chop = CHOP(now); bool do_jacobian = JACOBIAN(now); bool do_normals = NORMALS(now) && !do_chop; if (!_ocean || _ocean_needs_rebuild) { if (_ocean) { delete _ocean; } if (_ocean_context) { delete _ocean_context; } _ocean = new drw::Ocean(gridres,gridres,stepsize,stepsize, V(0),L(0),1.0,W(0),1-DAMP(0),ALIGN(0), DEPTH(0),SEED(0)); _ocean_scale = _ocean->get_height_normalize_factor(); _ocean_context = _ocean->new_context(true,do_chop,do_normals,do_jacobian); _ocean_needs_rebuild = false; // std::cout << "######### SOP, rebuilt ocean, norm_factor = " << _ocean_scale // << " chop = " << do_chop // << " norm = " << do_normals // << " jacobian = " << do_jacobian // << std::endl; } float chop_amount = CHOPAMOUNT(now); // sum up the waves at this timestep _ocean->update(TIME(now),*_ocean_context,true,do_chop,do_normals,do_jacobian, _ocean_scale * SCALE(now),chop_amount); bool linterp = ! INTERP(now); // get our attribute indices GA_RWAttributeRef normal_index; GA_RWAttributeRef jminus_index; GA_RWAttributeRef eminus_index; if (do_normals) { normal_index = gdp->addNormalAttribute(GEO_POINT_DICT); } if (do_jacobian) { // jminus_index = gdp->addPointAttrib("mineigval",sizeof(float),GB_ATTRIB_FLOAT,0); // eminus_index = gdp->addPointAttrib("mineigvec",sizeof(UT_Vector3),GB_ATTRIB_VECTOR,0); jminus_index = gdp->addTuple(GA_STORE_REAL32,GA_ATTRIB_POINT,"mineigval",1,GA_Defaults(0)); eminus_index = gdp->addFloatTuple(GA_ATTRIB_POINT,"mineigvec",1,GA_Defaults(0)); } // this is not that fast, can it be done quicker ??? GA_FOR_ALL_GPOINTS(gdp, ppt) { UT_Vector4 p = ppt->getPos(); if (linterp) { _ocean_context->eval_xz(p(0),p(2)); } else { _ocean_context->eval2_xz(p(0),p(2)); } if (do_chop) { p.assign( p(0) + _ocean_context->disp[0], p(1) + _ocean_context->disp[1], p(2) + _ocean_context->disp[2] ); } else { // ppt->getPos()(1) += _ocean_context->disp[1]; UT_Vector4 tmp_p = ppt->getPos(); tmp_p(1) += _ocean_context->disp[1]; ppt->setPos(tmp_p); } if (do_normals) { /* UT_Vector3* normal = (UT_Vector3*) ppt->castAttribData<UT_Vector3>(normal_index); normal->assign(_ocean_context->normal[0], _ocean_context->normal[1], _ocean_context->normal[2]); normal->normalize(); */ ppt->getValue<UT_Vector3>(normal_index).assign(_ocean_context->normal[0], _ocean_context->normal[1], _ocean_context->normal[2]); ppt->getValue<UT_Vector3>(normal_index).normalize(); } if (do_jacobian) {/* float *js = (float*)ppt->castAttribData<float>(jminus_index); *js = _ocean_context->Jminus; UT_Vector3* eminus = (UT_Vector3*)ppt->castAttribData<UT_Vector3>(eminus_index); eminus->assign(_ocean_context->Eminus[0],0,_ocean_context->Eminus[1]); */ ppt->setValue<float>(jminus_index,_ocean_context->Jminus); ppt->getValue<UT_Vector3>(eminus_index).assign(_ocean_context->Eminus[0],0,_ocean_context->Eminus[1]); } ppt->setPos(p); }
/* * Do the shift of the next tabstop implied by * insertion so it expands. */ void vishft(void) { int tshft = 0; int j; register int i; register cell *tp = vtube0; register cell *up; short oldhold = hold; shft = value(TABSTOP); hold |= HOLDPUPD; if (!IM && !EI) { /* * Dumb terminals are easy, we just have * to retype the text. */ vigotoCL(tabend + shft); up = tp + tabend; for (i = tabend; i < linend; i++) vputchar(*up++); } else if (IN) { /* * CONCEPT-like terminals do most of the work for us, * we don't have to muck with simulation of multi-line * insert mode. Some of the shifting may come for free * also if the tabs don't have enough slack to take up * all the inserted characters. */ i = shft; slakused = inssiz - doomed; if (slakused > tabslack) { i -= slakused - tabslack; slakused -= tabslack; } if (i > 0 && tabend != linend) { tshft = i; vgotoCL(tabend); goim(); do vputchar(' ' | QUOTE); while (--i); } } else { /* * HP and Datamedia type terminals have to have multi-line * insert faked. Hack each segment after where we are * (going backwards to where we are.) We then can * hack the segment where the end of the first following * tab group is. */ for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) { vgotoCL(j * WCOLS); goim(); up = tp + j * WCOLS - shft; i = shft; do { if (*up) vputchar(*up++); else break; } while (--i); } vigotoCL(tabstart); i = shft - (inssiz - doomed); if (i > 0) { tabslack = inssiz - doomed; vcsync(); goim(); do vputchar(' '); while (--i); } } /* * Now do the data moving in the internal screen * image which is common to all three cases. */ tp += linend; up = tp + shft; i = linend - tabend; if (i > 0) do *--up = *--tp; while (--i); if (IN && tshft) { i = tshft; do *--up = ' ' | QUOTE; while (--i); } hold = oldhold; }
/* * Insert character c at current cursor position. * Multi-character inserts occur only as a result * of expansion of tabs (i.e. inssize == 1 except * for tabs) and code assumes this in several place * to make life simpler. */ int vinschar(int c) /* int c; /\* mjm: char --> int */ { register int i; register cell *tp; char *OIM; bool OXN; int noim, filler = 0; insmc1 = colsc(c) - 1; if ((!IM || !EI) && ((hold & HOLDQIK) || !value(REDRAW) || value(SLOWOPEN))) { /* * Don't want to try to use terminal * insert mode, or to try to fake it. * Just put the character out; the screen * will probably be wrong but we will fix it later. */ if (c == '\t') { vgotab(); return c; } vputchar(c); #ifdef MB if (insmc1 == 0 && (vtube0[destcol]&(TRIM|MULTICOL))==MULTICOL) vtube0[destcol] = INVBIT; #endif /* MB */ if (DEPTH(vcline) * WCOLS + !value(REDRAW) > (destline - LINE(vcline)) * WCOLS + destcol) return c; /* * The next line is about to be clobbered * make space for another segment of this line * (on an intelligent terminal) or just remember * that next line was clobbered (on a dumb one * if we don't care to redraw the tail. */ if (AL) { vnpins(0); } else { c = LINE(vcline) + DEPTH(vcline); if (c < LINE(vcline + 1) || c > WBOT) return c; i = destcol; vinslin(c, 1, vcline); DEPTH(vcline)++; vigoto(c, i); vprepins(); } return c; } /* * Compute the number of positions in the line image of the * current line. This is done from the physical image * since that is faster. Note that we have no memory * from insertion to insertion so that routines which use * us don't have to worry about moving the cursor around. */ if (*vtube0 == 0) linend = 0; else { /* * Search backwards for a non-null character * from the end of the displayed line. */ i = WCOLS * DEPTH(vcline); if (i == 0) i = WCOLS; tp = vtube0 + i; while (*--tp == 0) if (--i == 0) break; linend = i + insmc1; } /* * We insert at a position based on the physical location * of the output cursor. */ inscol = destcol + (destline - LINE(vcline)) * WCOLS; insmc0 = 0; #ifdef MB i = 0; while (inscol+i < LBSIZE && vtube0[inscol+i]&MULTICOL && (vtube0[inscol+insmc0+i]&(MULTICOL|TRIM)) != MULTICOL) i++; while (inscol+insmc0+i < LBSIZE && (vtube0[inscol+insmc0+i]&(MULTICOL|TRIM)) == MULTICOL) insmc0++; #endif /* MB */ if (c == '\t') { /* * Characters inserted from a tab must be * remembered as being part of a tab, but we can't * use QUOTE here since we really need to print blanks. * QUOTE|' ' is the representation of this. */ inssiz = tabcol(inscol+insmc0, value(TABSTOP)) - inscol - insmc0; c = ' ' | QUOTE; } else inssiz = 1; /* * If the text to be inserted is less than the number * of doomed positions, then we don't need insert mode, * rather we can just typeover. */ if (inssiz + insmc1 <= doomed) { endim(); if (inscol + insmc0 != linend) doomed -= inssiz + insmc1; #ifdef MB if (insmc1 == 0 && c != '\t' && vtube0[inscol+insmc0] & MULTICOL) vtube0[inscol+insmc0] = INVBIT; #endif /* MB */ do vputchar(c); while (--inssiz); return c; } /* * Have to really do some insertion, thus * stake out the bounds of the first following * group of tabs, computing starting position, * ending position, and the number of ``spaces'' therein * so we can tell how much it will squish. */ tp = vtube0 + inscol + insmc0; for (i = inscol + insmc0; i < linend; i++) { if (*tp++ & QUOTE) { --tp; break; } } tabstart = tabend = i; tabslack = 0; while (tabend < linend) { i = *tp++; if ((i & QUOTE) == 0) break; if ((i & (TRIM|MULTICOL)) == 0) tabslack++; tabsize++; tabend++; } tabsize = tabend - tabstart; /* * For HP's and DM's, e.g. tabslack has no meaning. */ if (!IN) tabslack = 0; #ifdef IDEBUG if (trace) { fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ", inscol, inssiz, tabstart); fprintf(trace, "tabend %d, tabslack %d, linend %d\n", tabend, tabslack, linend); } #endif OIM = IM; OXN = XN; noim = 0; #ifdef MB if (mb_cur_max > 1) { if (destcol + 1 + insmc1 == WCOLS + 1) { noim = 1; if (insmc1 == 1 && insmc0 == 0) filler = 1; } for (i = inscol; vtube0[i]; i++) if (i + 1 >= WCOLS && vtube0[i] & MULTICOL) { noim = 1; break; } } #endif /* MB */ if (noim) { endim(); IM = 0; XN = 0; } /* * The real work begins. */ slakused = 0; shft = 0; if (tabsize) { /* * There are tabs on this line. * If they need to expand, then the rest of the line * will have to be shifted over. In this case, * we will need to make sure there are no ``spaces'' * in the rest of the line (on e.g. CONCEPT-100) * and then grab another segment on the screen if this * line is now deeper. We then do the shift * implied by the insertion. */ if (inssiz >= doomed + tabcol(tabstart, value(TABSTOP)) - tabstart) { if (IN) vrigid(); vneedpos(value(TABSTOP)); vishft(); } } else if (inssiz + insmc1 > doomed) /* * No tabs, but line may still get deeper. */ vneedpos(inssiz + insmc1 - doomed); /* * Now put in the inserted characters. */ viin(c); /* * Now put the cursor in its final resting place. */ destline = LINE(vcline); destcol = inscol + inssiz + insmc1 + filler; vcsync(); if (IM != OIM) { IM = OIM; XN = OXN; } return c; }
void studrenDrawTriangle(S_Renderer *pRenderer, S_Coords *v1, S_Coords *v2, S_Coords *v3, S_Coords *n1, S_Coords *n2, S_Coords *n3, int x1, int y1, int x2, int y2, int x3, int y3 ) { S_StudentRenderer * renderer; /* ukazatel na studentsky renderer */ renderer = (S_StudentRenderer *)pRenderer; int minx, miny, maxx, maxy; int a1, a2, a3, b1, b2, b3, c1, c2, c3; int /*s1,*/ s2, s3; int x, y, e1, e2, e3; double alpha, beta, w1, w2, w3, z; S_RGBA col1, col2, col3, color; IZG_ASSERT(pRenderer && v1 && v2 && v3 && n1 && n2 && n3); /* vypocet barev ve vrcholech */ col1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1); col2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2); col3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3); /* obalka trojuhleniku */ minx = MIN(x1, MIN(x2, x3)); maxx = MAX(x1, MAX(x2, x3)); miny = MIN(y1, MIN(y2, y3)); maxy = MAX(y1, MAX(y2, y3)); /* oriznuti podle rozmeru okna */ miny = MAX(miny, 0); maxy = MIN(maxy, pRenderer->frame_h - 1); minx = MAX(minx, 0); maxx = MIN(maxx, pRenderer->frame_w - 1); /* vektory urcene vrcholy 1-2 a 1-3 */ a1 = x2 - x1; a3 = x3 - x1; b1 = y2 - y1; b3 = y3 - y1; /* overeni counterclockwise orientace troj. pomoci vektoroveho soucinu */ if ((a1 * b3 - b1 * a3) < 0) { /* spatna orientace -> prohodime vrcholy 2 a 3 */ SWAP(x2, x3); SWAP(y2, y3); /* a take barvy vrcholu */ SWAP(col2.red, col3.red); SWAP(col2.green, col3.green); SWAP(col2.blue, col3.blue); SWAP(col2.alpha, col3.alpha); } /* Pineduv alg. rasterizace troj. hranova fce je obecna rovnice primky Ax + By + C = 0 primku prochazejici body (x1, y1) a (x2, y2) urcime jako (y1 - y2)x + (x2 - x1)y + x1y2 - x2y1 = 0 */ /* normala primek - vektor kolmy k vektoru mezi dvema vrcholy, tedy (-dy, dx) */ a1 = y1 - y2; a2 = y2 - y3; a3 = y3 - y1; b1 = x2 - x1; b2 = x3 - x2; b3 = x1 - x3; /* koeficient C */ c1 = x1 * y2 - x2 * y1; c2 = x2 * y3 - x3 * y2; c3 = x3 * y1 - x1 * y3; /* vypocet hranove fce (vzdalenost od primky) pro protejsi body */ /*s1 = a1 * x3 + b1 * y3 + c1;*/ s2 = a2 * x1 + b2 * y1 + c2; s3 = a3 * x2 + b3 * y2 + c3; /* uprava koeficientu C pro korektni vyplnovani, viz "OpenGL top-left rule" */ /* https://books.google.cz/books?id=3ljRBQAAQBAJ&pg=PA73 */ if ((y1 == y2 && x2 > x1) || y2 < y1) { c1 -= 1; } if ((y2 == y3 && x3 > x2) || y3 < y2) { c2 -= 1; } if ((y3 == y1 && x1 > x3) || y1 < y3) { c3 -= 1; } // moje deklarace int * index; S_Frag tmp_frag; /* koeficienty pro barycentricke souradnice */ alpha = 1.0 / (ABS(s2) + 1); beta = 1.0 / (ABS(s3) + 1); /* vyplnovani... */ for (y = miny; y <= maxy; ++y) { /* inicilizace hranove fce v bode (minx, y) */ e1 = a1 * minx + b1 * y + c1; e2 = a2 * minx + b2 * y + c2; e3 = a3 * minx + b3 * y + c3; for (x = minx; x <= maxx; ++x) { if (e1 >= 0 && e2 >= 0 && e3 >= 0) { /* interpolace pomoci barycentrickych souradnic e1, e2, e3 je aktualni vzdalenost bodu (x, y) od primek */ w1 = alpha * e2; w2 = beta * e3; w3 = 1.0 - w1 - w2; /* interpolace z-souradnice */ z = w1 * v1->z + w2 * v2->z + w3 * v3->z; /* interpolace barvy */ color.red = ROUND2BYTE(w1 * col1.red + w2 * col2.red + w3 * col3.red); color.green = ROUND2BYTE(w1 * col1.green + w2 * col2.green + w3 * col3.green); color.blue = ROUND2BYTE(w1 * col1.blue + w2 * col2.blue + w3 * col3.blue); color.alpha = ROUND2BYTE(w1 * col1.alpha + w2 * col2.alpha + w3 * col3.alpha); /* vykresleni bodu */ if (z < DEPTH(pRenderer, x, y)) { /*PIXEL(pRenderer, x, y) = color; DEPTH(pRenderer, x, y) = z;*/ index = (int *)vecGetPtr(renderer->vecHeadBuff, y * renderer->base.frame_w + x); //tmp_index = *index; tmp_frag = makeFrag(color, z, *index); *index = fragvecPushBack(renderer->vecNodeBuff, tmp_frag); //printf("%d\n", fragvecGetPtr(renderer->vecNodeBuff, 0)->next); } } /* hranova fce o pixel vedle */ e1 += a1; e2 += a2; e3 += a3; } } /* Razeni a pocitani vyslednych barev */ // deklarace pro sorting int sortStart, sortIndex; int myDepth; // michani barev S_RGBA mixColor; double col_R, col_G, col_B, col_A; double aSrc; // pomocne fragmenty S_Frag * pattern; S_Frag myFragTMP; S_Frag * myFragment; // pruchod pro razeni for (y = miny; y <= maxy; ++y) { for (x = minx; x <= maxx; ++x) { // index byl deklarovan uz vyse index = (int *)(vecGetPtr(renderer->vecHeadBuff, y * renderer->base.frame_w + x)); if (*index != -1) { sortStart = *index; /* K razeni je pouzit radici algoritmus Select Sort */ while ((myFragment = fragvecGetPtr(renderer->vecNodeBuff, sortStart))->next != -1) { sortStart = myFragment->next; sortIndex = myFragment->next; // dokud se neprojde "pole" na sebe navazujicich(indexujicich) prvku while (sortIndex != -1) { pattern = fragvecGetPtr(renderer->vecNodeBuff, sortIndex); // dojde k prohozeni hodnot, najde-li se mensi hloubka if (pattern->depth < myFragment->depth) { myFragTMP.depth = myFragment->depth; myFragTMP.color = myFragment->color; myFragment->depth = pattern->depth; myFragment->color = pattern->color; pattern->depth = myFragTMP.depth; pattern->color = myFragTMP.color; } sortIndex = pattern->next; } } } } } // pruchod pro michani barev for (y = miny; y <= maxy; ++y) { for (x = minx; x <= maxx; ++x) { // index byl deklarovan uz vyse index = (int *)(vecGetPtr(renderer->vecHeadBuff, y * renderer->base.frame_w + x)); if (*index != -1) { sortStart = *index; // michani barvy myDepth = 0; col_R = 0.0; col_G = 0.0; col_B = 0.0; col_A = 1.0; while (sortStart != -1) { pattern = fragvecGetPtr(renderer->vecNodeBuff, sortStart); aSrc = pattern->color.alpha / 255.0; col_R = col_A * pattern->color.red + col_R; col_G = col_A * pattern->color.green + col_G; col_B = col_A * pattern->color.blue + col_B; col_A = (1.0 - aSrc) * col_A; sortStart = pattern->next; } mixColor.alpha = 255; mixColor.red = ROUND2BYTE(col_R); mixColor.green = ROUND2BYTE(col_G); mixColor.blue = ROUND2BYTE(col_B); PIXEL(pRenderer, x, y) = mixColor; DEPTH(pRenderer, x, y) = myDepth; } } } }
// . remove this node from the tree // . used to remove the last node and replace it with a higher scorer void TopTree::deleteNode ( int32_t i , uint8_t domHash ) { // sanity check if ( PARENT(i) == -2 ) { char *xx=NULL;*xx=0; } // get node //TopNode *t = &m_nodes[i]; // debug //if ( ! checkTree ( false ) ) { char *xx = NULL; *xx = 0; } //if ( i == 262 ) // log("HEY"); // if it was the low node, update it if ( i == m_lowNode ) { m_lowNode = getNext ( i ); if ( m_lowNode == -1 ) { log("toptree: toptree delete error node #%"INT32" " "domHash=%"INT32" because next node is -1 numnodes=%"INT32"", i,(int32_t)domHash,m_numUsedNodes); //char *xx=NULL;*xx=0; } //return; } } // update the vcount if ( m_domCount[domHash] < m_cap ) m_vcount -= 1.0; else if ( m_domCount[domHash] == m_cap ) m_vcount -= m_partial; // update the dom count m_domCount[domHash]--; // debug //if ( domHash == 0x35 ) // log("top: domCount down for 0x%"XINT32" now %"INT32"",domHash,m_domCount[domHash]); // parent of i int32_t iparent ; int32_t jparent ; // j will be the node that replace node #i int32_t j = i; // . now find a node to replace node #i // . get a node whose key is just to the right or left of i's key // . get i's right kid // . then get that kid's LEFT MOST leaf-node descendant // . this little routine is stolen from getNextNode(i) // . try to pick a kid from the right the same % of time as from left if ( ( m_pickRight && RIGHT(j) >= 0 ) || ( LEFT(j) < 0 && RIGHT(j) >= 0 ) ) { // try to pick a left kid next time m_pickRight = 0; // go to the right kid j = RIGHT ( j ); // now go left as much as we can while ( LEFT ( j ) >= 0 ) j = LEFT ( j ); // use node j (it's a leaf or has a right kid) goto gotReplacement; } // . now get the previous node if i has no right kid // . this little routine is stolen from getPrevNode(i) if ( LEFT(j) >= 0 ) { // try to pick a right kid next time m_pickRight = 1; // go to the left kid j = LEFT ( j ); // now go right as much as we can while ( RIGHT ( j ) >= 0 ) j = RIGHT ( j ); // use node j (it's a leaf or has a left kid) goto gotReplacement; } // . come here if i did not have any kids (i's a leaf node) // . get i's parent iparent = PARENT(i); // make i's parent, if any, disown him if ( iparent >= 0 ) { if ( LEFT(iparent) == i ) LEFT (iparent) = -1; else RIGHT(iparent) = -1; } // empty him PARENT(i) = -2; // . reset the depths starting at iparent and going up until unchanged // . will balance at pivot nodes that need it //if ( m_doBalancing ) setDepths ( iparent ); // debug //if ( ! checkTree ( false ) ) { char *xx = NULL; *xx = 0; } goto done; // . now replace node #i with node #j // . i should not equal j at this point gotReplacement: // . j's parent should take j's one kid // . that child should likewise point to j's parent // . j should only have <= 1 kid now because of our algorithm above // . if j's parent is i then j keeps his kid jparent = PARENT(j); if ( jparent != i ) { // parent: if j is my left kid, then i take j's right kid // otherwise, if j is my right kid, then i take j's left kid if ( LEFT ( jparent ) == j ) { LEFT ( jparent ) = RIGHT ( j ); if (RIGHT(j)>=0) PARENT ( RIGHT(j) ) = jparent; } else { RIGHT ( jparent ) = LEFT ( j ); if (LEFT (j)>=0) PARENT ( LEFT(j) ) = jparent; } } // . j inherits i's children (providing i's child is not j) // . those children's parent should likewise point to j if ( LEFT (i) != j ) { LEFT (j) = LEFT (i); if ( LEFT(j) >= 0 ) PARENT(LEFT (j)) = j; } if ( RIGHT(i) != j ) { RIGHT(j) = RIGHT(i); if ( RIGHT(j) >= 0 ) PARENT(RIGHT(j)) = j; } // j becomes the kid of i's parent, if any iparent = PARENT(i); if ( iparent >= 0 ) { if ( LEFT(iparent) == i ) LEFT (iparent) = j; else RIGHT(iparent) = j; } // iparent may be -1 PARENT(j) = iparent; // if i was the head node now j becomes the head node if ( m_headNode == i ) m_headNode = j; // kill i PARENT(i) = -2; // return if we don't have to balance //if ( ! m_doBalancing ) return; // our depth becomes that of the node we replaced, unless moving j // up to i decreases the total depth, in which case setDepths() fixes DEPTH ( j ) = DEPTH ( i ); // debug msg //fprintf(stderr,"... replaced %"INT32" it with %"INT32" (-1 means none)\n",i,j); // . recalculate depths starting at old parent of j // . stops at the first node to have the correct depth // . will balance at pivot nodes that need it if ( jparent != i ) setDepths ( jparent ); else setDepths ( j ); done: // the guy we are deleting is now the first "empty node" and // he must link to the old empty node m_nodes[i].m_right = m_emptyNode; m_emptyNode = i; //m_lastKickedOutDocId = m_nodes[i].m_docId; // count it m_numUsedNodes--; // flag it m_kickedOutDocIds = true; // debug //if ( ! checkTree ( true ) ) { char *xx = NULL; *xx = 0; } }
/* Graph reduction function. Destructively modifies the graph passed in. */ enum graphReductionResult reduce_graph(struct node *root) { enum graphReductionResult r = UNKNOWN; struct spine_stack *stack = NULL; unsigned long reduction_counter = 0; int max_redex_count = 0; /* Used to decide what to do next: * at an application (interior node of graph) * you can take the left branch into subtree, * take the right branch, or pop the node and * go "up" the tree. */ enum Direction { DIR_LEFT, DIR_RIGHT, DIR_UP }; enum Direction dir = DIR_LEFT; stack = new_spine_stack(64); /* root constitutes the "dummy" root node */ root->updateable = root->left_addr; pushnode(stack, root, 1); D print_graph(root, 0, TOPNODE(stack)->sn); while (STACK_NOT_EMPTY(stack)) { int pop_stack_cnt = 1; int performed_reduction = 0; struct node *topnode = TOPNODE(stack); const char *atom_name = NULL; switch (topnode->typ) { case APPLICATION: switch (dir) { case DIR_LEFT: topnode->updateable = topnode->left_addr; pushnode(stack, topnode->left, 0); D printf("push left branch on stack, depth now %d\n", DEPTH(stack)); pop_stack_cnt = 0; break; case DIR_RIGHT: topnode->updateable = topnode->right_addr; pushnode(stack, topnode->right, 2); D printf("push right branch on stack, depth now %d\n", DEPTH(stack)); pop_stack_cnt = 0; break; case DIR_UP: break; } break; case ATOM: /* node->typ indicates a combinator, which can comprise a built-in, * or it can comprise a mere variable. Let node->rule decide. */ if (topnode->rule && DEPTH(stack) >= (topnode->rule->required_depth + 2)) { D { atom_name = topnode->name; printf("%s reduction (sn %d), stack depth %d, before: ", topnode->name, topnode->sn, DEPTH(stack) ); print_graph(root->left, topnode->sn, topnode->sn); } pop_stack_cnt = topnode->rule->required_depth + 1; perform_reduction(stack); performed_reduction = 1; } else D { printf("%s atom, stack depth %d, required depth %d.\n", topnode->name, DEPTH(stack), topnode->rule? topnode->rule->required_depth + 2: -1 ); } if (performed_reduction) SS; break; }
/* * Put the character c on the screen at the current cursor position. * This routine handles wraparound and scrolling and understands not * to roll when splitw is set, i.e. we are working in the echo area. * There is a bunch of hacking here dealing with the difference between * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also * code to deal with terminals which overstrike, including CRT's where * you can erase overstrikes with some work. CRT's which do underlining * implicitly which has to be erased (like CONCEPTS) are also handled. */ int vputchar(register int c) { register cell *tp; register int d, m, n; #ifndef BIT8 c &= (QUOTE|TRIM); #endif #ifdef TRACE if (trace) tracec(c); #endif /* Fix problem of >79 chars on echo line. */ if (destcol >= WCOLS-1 && splitw && destline == WECHO) pofix(); #ifdef MB if (mb_cur_max > 1) { if (c == MULTICOL) return c; /* * If a multicolumn character extends beyond the screen * width, it must be put on the next line. A tilde is * printed as an indicator but must disappear when the * text is moved at a later time. */ if (c == ('~'|INVBIT|QUOTE)) c = '~'|INVBIT; else if (c == ('~'|INVBIT)) return c; else if (destcol < WCOLS && destcol + colsc(c==QUOTE ? ' ' : c&TRIM&~MULTICOL) - 1 >= WCOLS) vputchar('~'|INVBIT|QUOTE); } #endif /* MB */ if (destcol >= WCOLS) { destline += destcol / WCOLS; destcol %= WCOLS; } if (destline > WBOT && (!splitw || destline > WECHO)) vrollup(destline); tp = vtube[destline] + destcol; if (c == QUOTE) { if (insmode) { /* * When in insert mode, tabs have to expand * to real, printed blanks. */ c = ' ' | QUOTE; goto def; } if (*tp == 0) { /* * A ``space''. */ if ((hold & HOLDPUPD) == 0) *tp = QUOTE; destcol++; return c; } /* * A ``space'' ontop of a part of a tab. */ if (*tp & QUOTE) { destcol++; return c; } c = ' ' | QUOTE; goto def; } #ifdef notdef #ifdef BIT8 if (c == ' ' | QUOTE) { c = ' '; goto def; } #endif #endif switch (c) { case '\t': vgotab(); return c; case ' ': /* * We can get away without printing a space in a number * of cases, but not always. We get away with doing nothing * if we are not in insert mode, and not on a CONCEPT-100 * like terminal, and either not in hardcopy open or in hardcopy * open on a terminal with no overstriking, provided, * in all cases, that nothing has ever been displayed * at this position. Ugh. */ if (!insmode && !IN && (state != HARDOPEN || OS) && (*tp"E)) { *tp = ' '; destcol++; return c; } goto def; def: default: d = *tp & TRIM; /* * Now get away with doing nothing if the characters * are the same, provided we are not in insert mode * and if we are in hardopen, that the terminal has overstrike. */ if ((d & ~MULTICOL) == (c & TRIM & ~MULTICOL) && !insmode && (state != HARDOPEN || OS) && c != MULTICOL) { n = colsc(d); for (m = 1; m < n; m++) if ((tp[m] & (MULTICOL|TRIM)) != MULTICOL) break; if (m == n) { if ((hold & HOLDPUPD) == 0) *tp = c | (n > 1 ? MULTICOL : 0); destcol += n; return c; } } /* * Backwards looking optimization. * The low level cursor motion routines will use * a cursor motion right sequence to step 1 character * right. On, e.g., a DM3025A this is 2 characters * and printing is noticeably slower at 300 baud. * Since the low level routines are not allowed to use * spaces for positioning, we discover the common * case of a single space here and force a space * to be printed. */ if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) { vputc(' '); outcol++; } /* * This is an inline expansion a call to vcsync() dictated * by high frequency in a profile. */ if (outcol != destcol || outline != destline) vgoto(destline, destcol); /* * Deal with terminals which have overstrike. * We handle erasing general overstrikes, erasing * underlines on terminals (such as CONCEPTS) which * do underlining correctly automatically (e.g. on nroff * output), and remembering, in hardcopy mode, * that we have overstruct something. */ if (!insmode && d && d != ' ' && d != (c & TRIM)) { if (EO && (OS || UL && (c == '_' || d == '_'))) { vputc(' '); outcol++, destcol++; back1(); } else rubble = 1; } /* * Unless we are just bashing characters around for * inner working of insert mode, update the display. */ if ((hold & HOLDPUPD) == 0) *tp = c; /* * In insert mode, put out the IC sequence, padded * based on the depth of the current line. * A terminal which had no real insert mode, rather * opening a character position at a time could do this. * Actually should use depth to end of current line * but this rarely matters. */ #ifdef notdef if (insmode) #else /* * It seems today's termcap writers consider this * an either-or situation; if both im and ic * are used vi puts out additional spaces. * * SVR4 ex does not include this change. If it hits * your terminal, change back to the old way and * mail me a description. * * GR July 2000 */ if (insmode && (!IM || !*IM)) #endif /* !notdef */ { n = colsc(c&TRIM); for (m = 0; m < n; m++) vputp(IC, DEPTH(vcline)); } vputc(c & TRIM); /* * In insert mode, IP is a post insert pad. */ if (insmode) vputp(IP, DEPTH(vcline)); destcol++, outcol++; /* * CONCEPT braindamage in early models: after a wraparound * the next newline is eaten. It's hungry so we just * feed it now rather than worrying about it. * Fixed to use return linefeed to work right * on vt100/tab132 as well as concept. */ if (XN && outcol % WCOLS == 0) { vputc('\r'); vputc('\n'); } } #ifdef MB if (mb_cur_max > 1 && (d = colsc(c&TRIM&~MULTICOL)) > 1) { if ((hold & HOLDPUPD) == 0) *tp |= MULTICOL; while (--d) { if ((hold & HOLDPUPD) == 0) *++tp = MULTICOL; destcol++; outcol++; } } #endif /* MB */ return c; }
// returns false if tree had problem, true otherwise bool TopTree::checkTree ( bool printMsgs ) { // now check parent kid correlations for ( int32_t i = 0 ; i < m_numUsedNodes ; i++ ) { // skip node if parents is -2 (unoccupied) if ( PARENT(i) == -2 ) continue; // if no left/right kid it MUST be -1 if ( LEFT(i) < -1 ) return log("query: toptree: checktree: left " "kid %"INT32" < -1",i); if ( RIGHT(i) < -1 ) return log("query: toptree: checktree: right " "kid %"INT32" < -1",i); // check left kid if ( LEFT(i) >= 0 && PARENT(LEFT(i)) != i ) return log("query: toptree: checktree: tree has " "error %"INT32"",i); // then right kid if ( RIGHT(i) >= 0 && PARENT(RIGHT(i)) != i ) return log("query: toptree: checktree: tree has " "error2 %"INT32"",i); } // now return if we aren't doing active balancing //if ( ! DEPTH ) return true; // debug -- just always return now if ( printMsgs ) log("***m_headNode=%"INT32", m_numUsedNodes=%"INT32"", m_headNode,m_numUsedNodes); // verify that parent links correspond to kids for ( int32_t i = 0 ; i < m_numUsedNodes ; i++ ) { int32_t P = PARENT (i); if ( P == -2 ) continue; // deleted node if ( P == -1 && i != m_headNode ) return log("query: toptree: checktree: node %"INT32" has " "no parent",i); // check kids if ( P>=0 && LEFT(P) != i && RIGHT(P) != i ) return log("query: toptree: checktree: node %"INT32"'s " "parent disowned",i); // ensure i goes back to head node int32_t j = i; while ( j >= 0 ) { if ( j == m_headNode ) break; j = PARENT(j); } if ( j != m_headNode ) return log("query: toptree: checktree: node %"INT32"'s no " "head node above",i); if ( printMsgs ) fprintf(stderr,"***node=%"INT32" left=%"INT32" rght=%"INT32" " "prnt=%"INT32", depth=%"INT32"\n", i,LEFT(i),RIGHT(i),PARENT(i), (int32_t)DEPTH(i)); //ensure depth int32_t newDepth = computeDepth ( i ); if ( DEPTH(i) != newDepth ) return log("query: toptree: checktree: node %"INT32"'s " "depth should be %"INT32"",i,newDepth); } if ( printMsgs ) log("query: ---------------"); // no problems found return true; }
static VtFile * vtfilealloc(VtCache *c, VtBlock *b, VtFile *p, u32int offset, int mode) { int epb; u32int size; VtEntry e; VtFile *r; assert(p==nil || ISLOCKED(p)); if(p == nil){ assert(offset == 0); epb = 1; }else epb = p->dsize / VtEntrySize; if(b->type != VtDirType){ werrstr("bad block type %#uo", b->type); return nil; } /* * a non-active entry is the only thing that * can legitimately happen here. all the others * get prints. */ if(vtentryunpack(&e, b->data, offset % epb) < 0){ fprint(2, "vtentryunpack failed: %r (%.*H)\n", VtEntrySize, b->data+VtEntrySize*(offset%epb)); return nil; } if(!(e.flags & VtEntryActive)){ werrstr("entry not active"); return nil; } if(DEPTH(e.type) < sizetodepth(e.size, e.psize, e.dsize)){ fprint(2, "depth %ud size %llud psize %ud dsize %ud\n", DEPTH(e.type), e.size, e.psize, e.dsize); werrstr("bad depth"); return nil; } size = vtcacheblocksize(c); if(e.dsize > size || e.psize > size){ werrstr("block sizes %ud, %ud bigger than cache block size %ud", e.psize, e.dsize, size); return nil; } r = vtmallocz(sizeof(VtFile)); r->c = c; r->mode = mode; r->dsize = e.dsize; r->psize = e.psize; r->gen = e.gen; r->dir = (e.type & VtTypeBaseMask) == VtDirType; r->ref = 1; r->parent = p; if(p){ qlock(&p->lk); assert(mode == VtOREAD || p->mode == VtORDWR); p->ref++; qunlock(&p->lk); }else{ assert(b->addr != NilBlock); r->local = 1; } memmove(r->score, b->score, VtScoreSize); r->offset = offset; r->epb = epb; return r; }
// this is the same as above but LEFT and RIGHT are swapped int32_t TopTree::rotateLeft ( int32_t i ) { // i's left kid's LEFT kid takes his place int32_t A = i; int32_t N = RIGHT ( A ); int32_t W = RIGHT ( N ); int32_t X = LEFT ( N ); int32_t Q = -1; int32_t T = -1; if ( X >= 0 ) { Q = RIGHT ( X ); T = LEFT ( X ); } // let AP be A's parent int32_t AP = PARENT ( A ); // whose the bigger subtree, W or X? (depth includes W or X itself) int32_t Wdepth = 0; int32_t Xdepth = 0; if ( W >= 0 ) Wdepth = DEPTH(W); if ( X >= 0 ) Xdepth = DEPTH(X); // debug msg //fprintf(stderr,"A=%"INT32" AP=%"INT32" N=%"INT32" W=%"INT32" X=%"INT32" Q=%"INT32" T=%"INT32" " //"Wdepth=%"INT32" Xdepth=%"INT32"\n",A,AP,N,W,X,Q,T,Wdepth,Xdepth); // goto Xdeeper if X is deeper if ( Wdepth < Xdepth ) goto Xdeeper; // N's parent becomes A's parent PARENT ( N ) = AP; // A's parent becomes N PARENT ( A ) = N; // X's parent becomes A if ( X >= 0 ) PARENT ( X ) = A; // A's parents kid becomes N if ( AP >= 0 ) { if ( RIGHT ( AP ) == A ) RIGHT ( AP ) = N; else LEFT ( AP ) = N; } // if A had no parent, it was the headNode else { //fprintf(stderr,"changing head node from %"INT32" to %"INT32"\n", //m_headNode,N); m_headNode = N; } // N's LEFT kid becomes A LEFT ( N ) = A; // A's RIGHT kid becomes X RIGHT ( A ) = X; // . compute A's depth from it's X and B kids // . it should be one less if Xdepth smaller than Wdepth // . might set DEPTH(A) to computeDepth(A) if we have problems if ( Xdepth < Wdepth ) DEPTH ( A ) -= 2; else DEPTH ( A ) -= 1; // N gains a depth iff W and X were of equal depth if ( Wdepth == Xdepth ) DEPTH ( N ) += 1; // now we're done, return the new pivot that replaced A return N; // come here if X is deeper Xdeeper: // X's parent becomes A's parent PARENT ( X ) = AP; // A's parent becomes X PARENT ( A ) = X; // N's parent becomes X PARENT ( N ) = X; // Q's parent becomes N if ( Q >= 0 ) PARENT ( Q ) = N; // T's parent becomes A if ( T >= 0 ) PARENT ( T ) = A; // A's parent's kid becomes X if ( AP >= 0 ) { if ( RIGHT ( AP ) == A ) RIGHT ( AP ) = X; else LEFT ( AP ) = X; } // if A had no parent, it was the headNode else { //fprintf(stderr,"changing head node2 from %"INT32" to %"INT32"\n", //m_headNode,X); m_headNode = X; } // A's RIGHT kid becomes T RIGHT ( A ) = T; // N's LEFT kid becomes Q LEFT ( N ) = Q; // X's RIGHT kid becomes N RIGHT ( X ) = N; // X's LEFT kid becomes A LEFT ( X ) = A; // X's depth increases by 1 since it gained 1 level of 2 new kids DEPTH ( X ) += 1; // N's depth decreases by 1 DEPTH ( N ) -= 1; // A's depth decreases by 2 DEPTH ( A ) -= 2; // now we're done, return the new pivot that replaced A return X; }
static int shrinkdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth) { VtBlock *b, *nb, *ob, *rb; VtEntry oe; assert(ISLOCKED(r)); assert(depth <= VtPointerDepth); rb = vtcacheglobal(r->c, e->score, e->type); if(rb == nil) return -1; /* * Walk down to the new root block. * We may stop early, but something is better than nothing. */ oe = *e; ob = nil; b = rb; for(; DEPTH(e->type) > depth; e->type--){ nb = vtcacheglobal(r->c, b->data, e->type-1); if(nb == nil) break; if(ob!=nil && ob!=rb) vtblockput(ob); ob = b; b = nb; } if(b == rb){ vtblockput(rb); return 0; } /* * Right now, e points at the root block rb, b is the new root block, * and ob points at b. To update: * * (i) change e to point at b * (ii) zero the pointer ob -> b * (iii) free the root block * * p (the block containing e) must be written before * anything else. */ /* (i) */ memmove(e->score, b->score, VtScoreSize); vtentrypack(e, p->data, r->offset % r->epb); /* (ii) */ memmove(ob->data, vtzeroscore, VtScoreSize); /* (iii) */ vtblockput(rb); if(ob!=nil && ob!=rb) vtblockput(ob); vtblockput(b); if(DEPTH(e->type) == depth) return 0; return -1; }
void vappend(int ch, int cnt, int indent) { int i; unsigned char *gcursor; bool escape; int repcnt, savedoomed; short oldhold = hold; int savecnt = cnt; line *startsrcline; int startsrccol, endsrccol; int gotNL = 0; int imultlinecnt = 0; int omultlinecnt = 0; if ((savecnt > 1) && (ch == 'o' || ch == 'O')) { omultlinecnt = 1; } #ifdef XPG6 if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I')) imultlinecnt = 1; #endif /* XPG6 */ /* * Before a move in hardopen when the line is dirty * or we are in the middle of the printed representation, * we retype the line to the left of the cursor so the * insert looks clean. */ if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) { rubble = 1; gcursor = cursor; i = *gcursor; *gcursor = ' '; wcursor = gcursor; (void) vmove(); *gcursor = i; } /* * If vrep() passed indent = 0, this is the 'r' command, * so don't autoindent until the last char. */ vaifirst = indent == 0; /* * Handle replace character by (eventually) * limiting the number of input characters allowed * in the vgetline routine. */ if (ch == 'r') repcnt = 2; else repcnt = 0; /* * If an autoindent is specified, then * generate a mixture of blanks to tabs to implement * it and place the cursor after the indent. * Text read by the vgetline routine will be placed in genbuf, * so the indent is generated there. */ if (value(vi_AUTOINDENT) && indent != 0) { unsigned char x; gcursor = genindent(indent); *gcursor = 0; vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf)); } else { gcursor = genbuf; *gcursor = 0; if (ch == 'o') vfixcurs(); } /* * Prepare for undo. Pointers delimit inserted portion of line. */ vUA1 = vUA2 = cursor; /* * If we are not in a repeated command and a ^@ comes in * then this means the previous inserted text. * If there is none or it was too long to be saved, * then beep() and also arrange to undo any damage done * so far (e.g. if we are a change.) */ switch (ch) { case 'r': break; case 'a': /* * TRANSLATION_NOTE * "A" is a terse mode message corresponding to * "APPEND MODE". * Translated message of "A" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("A")); } else { vshowmode(gettext("APPEND MODE")); } break; case 's': /* * TRANSLATION_NOTE * "S" is a terse mode message corresponding to * "SUBSTITUTE MODE". * Translated message of "S" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("S")); } else { vshowmode(gettext("SUBSTITUTE MODE")); } break; case 'c': /* * TRANSLATION_NOTE * "C" is a terse mode message corresponding to * "CHANGE MODE". * Translated message of "C" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("C")); } else { vshowmode(gettext("CHANGE MODE")); } break; case 'R': /* * TRANSLATION_NOTE * "R" is a terse mode message corresponding to * "REPLACE MODE". * Translated message of "R" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("R")); } else { vshowmode(gettext("REPLACE MODE")); } break; case 'o': /* * TRANSLATION_NOTE * "O" is a terse mode message corresponding to * "OPEN MODE". * Translated message of "O" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("O")); } else { vshowmode(gettext("OPEN MODE")); } break; case 'i': /* * TRANSLATION_NOTE * "I" is a terse mode message corresponding to * "INSERT MODE" and the following "INPUT MODE". * Translated message of "I" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INSERT MODE")); } break; default: /* * TRANSLATION_NOTE * "I" is a terse mode message corresponding to * "INPUT MODE" and the previous "INSERT MODE". * Translated message of "I" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INPUT MODE")); } } ixlatctl(1); if ((vglobp && *vglobp == 0) || peekbr()) { if (INS[128] == 0200) { (void) beep(); if (!splitw) ungetkey('u'); doomed = 0; hold = oldhold; return; } /* * Unread input from INS. * An escape will be generated at end of string. * Hold off n^^2 type update on dumb terminals. */ vglobp = INS; inscdcnt = INSCDCNT; hold |= HOLDQIK; } else if (vglobp == 0) { /* * Not a repeated command, get * a new inserted text for repeat. */ INS[0] = 0; INS[128] = 0; INSCDCNT = 0; } /* * For wrapmargin to hack away second space after a '.' * when the first space caused a line break we keep * track that this happened in gobblebl, which says * to gobble up a blank silently. */ gobblebl = 0; startsrcline = dot; startsrccol = cursor - linebuf; /* * Text gathering loop. * New text goes into genbuf starting at gcursor. * cursor preserves place in linebuf where text will eventually go. */ if (*cursor == 0 || state == CRTOPEN) hold |= HOLDROL; for (;;) { if (ch == 'r' && repcnt == 0) escape = 0; else { ixlatctl(1); /* * When vgetline() returns, gcursor is * pointing to '\0' and vgetline() has * read an ESCAPE or NL. */ gcursor = vgetline(repcnt, gcursor, &escape, ch); if (escape == '\n') { gotNL = 1; #ifdef XPG6 if (ch == 'r') { /* * XPG6 assertion 313 [count]r\n : * Arrange to set cursor correctly. */ endsrccol = gcursor - genbuf - 1; } #endif /* XPG6 */ } else { /* * Upon escape, gcursor is pointing to '\0' * terminating the string in genbuf. */ endsrccol = gcursor - genbuf - 1; } ixlatctl(0); /* * After an append, stick information * about the ^D's and ^^D's and 0^D's in * the repeated text buffer so repeated * inserts of stuff indented with ^D as backtab's * can work. */ if (HADUP) addtext("^"); else if (HADZERO) addtext("0"); if(!vglobp) INSCDCNT = CDCNT; while (CDCNT > 0) { addtext("\004"); CDCNT--; } if (gobbled) addtext(" "); addtext(ogcursor); } repcnt = 0; /* * Smash the generated and preexisting indents together * and generate one cleanly made out of tabs and spaces * if we are using autoindent and this isn't 'r' command. */ if (!vaifirst && value(vi_AUTOINDENT)) { i = fixindent(indent); if (!HADUP) indent = i; gcursor = strend(genbuf); } /* * Set cnt to 1 to avoid repeating the text on the same line. * Do this for commands 'i', 'I', 'a', and 'A', if we're * inserting anything with a newline for XPG6. Always do this * for commands 'o' and 'O'. */ if ((imultlinecnt && gotNL) || omultlinecnt) { cnt = 1; } /* * Limit the repetition count based on maximum * possible line length; do output implied * by further count (> 1) and cons up the new line * in linebuf. */ cnt = vmaxrep(ch, cnt); /* * cursor points to linebuf * Copy remaining old text (cursor) in original * line to after new text (gcursor + 1) in genbuf. */ CP(gcursor + 1, cursor); /* * For [count] r \n command, when replacing [count] chars * with '\n', this loop replaces [count] chars with "". */ do { /* cp new text (genbuf) into linebuf (cursor) */ CP(cursor, genbuf); if (cnt > 1) { int oldhold = hold; Outchar = vinschar; hold |= HOLDQIK; viprintf("%s", genbuf); hold = oldhold; Outchar = vputchar; } /* point cursor after new text in linebuf */ cursor += gcursor - genbuf; } while (--cnt > 0); endim(); vUA2 = cursor; /* add the remaining old text after the cursor */ if (escape != '\n') CP(cursor, gcursor + 1); /* * If doomed characters remain, clobber them, * and reopen the line to get the display exact. * eg. c$ to change to end of line */ if (state != HARDOPEN) { DEPTH(vcline) = 0; savedoomed = doomed; if (doomed > 0) { int cind = cindent(); physdc(cind, cind + doomed); doomed = 0; } if(MB_CUR_MAX > 1) rewrite = _ON; i = vreopen(LINE(vcline), lineDOT(), vcline); if(MB_CUR_MAX > 1) rewrite = _OFF; #ifdef TRACE if (trace) fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed); #endif if (ch == 'R') doomed = savedoomed; } /* * Unless we are continuing on to another line * (got a NL), break out of the for loop (got * an ESCAPE). */ if (escape != '\n') { vshowmode(""); break; } /* * Set up for the new line. * First save the current line, then construct a new * first image for the continuation line consisting * of any new autoindent plus the pushed ahead text. */ killU(); addtext(gobblebl ? " " : "\n"); /* save vutmp (for undo state) into temp file */ vsave(); cnt = 1; if (value(vi_AUTOINDENT)) { if (value(vi_LISP)) indent = lindent(dot + 1); else if (!HADUP && vaifirst) indent = whitecnt(linebuf); vaifirst = 0; strcLIN(vpastwh(gcursor + 1)); gcursor = genindent(indent); *gcursor = 0; if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2]) gcursor = genbuf; CP(gcursor, linebuf); } else { /* * Put gcursor at start of genbuf to wipe * out previous line in preparation for * the next vgetline() loop. */ CP(genbuf, gcursor + 1); gcursor = genbuf; } /* * If we started out as a single line operation and are now * turning into a multi-line change, then we had better yank * out dot before it changes so that undo will work * correctly later. */ if (FIXUNDO && vundkind == VCHNG) { vremote(1, yank, 0); undap1--; } /* * Now do the append of the new line in the buffer, * and update the display, ie: append genbuf to * the file after dot. If slowopen * we don't do very much. */ vdoappend(genbuf); vundkind = VMANYINS; vcline++; if (state != VISUAL) vshow(dot, NOLINE); else { i += LINE(vcline - 1); vopen(dot, i); if (value(vi_SLOWOPEN)) vscrap(); else vsync1(LINE(vcline)); } switch (ch) { case 'r': break; case 'a': if (value(vi_TERSE)) { vshowmode(gettext("A")); } else { vshowmode(gettext("APPEND MODE")); } break; case 's': if (value(vi_TERSE)) { vshowmode(gettext("S")); } else { vshowmode(gettext("SUBSTITUTE MODE")); } break; case 'c': if (value(vi_TERSE)) { vshowmode(gettext("C")); } else { vshowmode(gettext("CHANGE MODE")); } break; case 'R': if (value(vi_TERSE)) { vshowmode(gettext("R")); } else { vshowmode(gettext("REPLACE MODE")); } break; case 'i': if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INSERT MODE")); } break; case 'o': if (value(vi_TERSE)) { vshowmode(gettext("O")); } else { vshowmode(gettext("OPEN MODE")); } break; default: if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INPUT MODE")); } } strcLIN(gcursor); /* zero genbuf */ *gcursor = 0; cursor = linebuf; vgotoCL(nqcolumn(cursor - 1, genbuf)); } /* end for (;;) loop in vappend() */ if (imultlinecnt && gotNL) { imultlinerep(savecnt, startsrcline, startsrccol, endsrccol); } else if (omultlinecnt) { omultlinerep(savecnt, startsrcline, endsrccol); #ifdef XPG6 } else if (savecnt > 1 && ch == 'r' && gotNL) { /* * XPG6 assertion 313 & 254 : Position cursor for [count]r\n * then insert [count -1] newlines. */ endsrccol = gcursor - genbuf - 1; rmultlinerep(savecnt, endsrccol); #endif /* XPG6 */ } /* * All done with insertion, position the cursor * and sync the screen. */ hold = oldhold; if ((imultlinecnt && gotNL) || omultlinecnt) { fixdisplay(); #ifdef XPG6 } else if (savecnt > 1 && ch == 'r' && gotNL) { fixdisplay(); /* * XPG6 assertion 313 & 254 [count]r\n : Set flag to call * fixdisplay() after operate() has finished. To be sure that * the text (after the last \n followed by an indent) is always * displayed, fixdisplay() is called right before getting * the next command. */ redisplay = 1; #endif /* XPG6 */ } else if (cursor > linebuf) { cursor = lastchr(linebuf, cursor); #ifdef XPG6 /* * XPG6 assertion 313 & 254 [count]r\n : * For 'r' command, when the replacement char causes new * lines to be created, point cursor to first non-blank. * The old code, ie: cursor = lastchr(linebuf, cursor); * set cursor to the blank before the first non-blank * for r\n */ if (ch == 'r' && gotNL && isblank((int)*cursor)) ++cursor; #endif /* XPG6 */ } if (state != HARDOPEN) vsyncCL(); else if (cursor > linebuf) back1(); doomed = 0; wcursor = cursor; (void) vmove(); }
void XDrawString_90(XWindow *xw, Drawable d, int x, int y, char *string, int length) { int i, j; XCharStruct size; unsigned int width, height; unsigned int x0, y0; XImage *in, *out; Pixmap pix; XGCValues val; XGetGCValues(DISPLAY(xw), xw->gc, GCForeground | GCBackground, &val); XTextSize(xw->font->font_core, string, length, &size); width = -size.lbearing + size.rbearing; height = size.ascent + size.descent; x0 = -size.lbearing; y0 = size.ascent; pix = XCreatePixmap(DISPLAY(xw), ROOT(xw), width, height, DEPTH(xw)); /* Background Fill */ XSetForeground(DISPLAY(xw), xw->gc, val.background); XFillRectangle(DISPLAY(xw), pix, xw->gc, 0, 0, width, height); XSetForeground(DISPLAY(xw), xw->gc, val.foreground); XDrawString(DISPLAY(xw), pix, xw->gc, x0, y0, string, length); /* Convert from pixmap to image */ in = XGetImage(DISPLAY(xw), pix, 0,0, width, height, AllPlanes, ZPixmap); XFreePixmap(DISPLAY(xw), pix); /* Create Image with Width and Height exchanged */ out = XCreateImage(DISPLAY(xw), VISUAL(xw), DEPTH(xw), ZPixmap, 0, NULL, height, width, 32, 0); out->data = (char *) malloc(sizeof(char) * width * out->bytes_per_line); /* "Rotate" Image */ for(j = 0; j < (int)height; j++) { for(i = 0; i < (int)width; i++) { /* width - i - 1 : Flip the Image Vertically */ XPutPixel(out, j, width - i - 1, XGetPixel(in, i, j)); } } pix = XCreatePixmap(DISPLAY(xw), ROOT(xw), height, width, DEPTH(xw)); XPutImage(DISPLAY(xw), pix, xw->gc, out, 0, 0, 0, 0, height, width); XCopyArea(DISPLAY(xw), pix, d, xw->gc, 0, 0, height, width, x, y); XFreePixmap(DISPLAY(xw), pix); XDestroyImage(out); XDestroyImage(in); }
void studrenDrawTriangle(S_Renderer *pRenderer, S_Coords *v1, S_Coords *v2, S_Coords *v3, S_Coords *n1, S_Coords *n2, S_Coords *n3, S_Coords *t0, S_Coords *t1, S_Coords *t2, int x1, int y1, int x2, int y2, int x3, int y3, double h1, double h2, double h3 ) { int minx, miny, maxx, maxy; int a1, a2, a3, b1, b2, b3, c1, c2, c3; int s1, s2, s3; int x, y, e1, e2, e3; double alpha, beta, gamma, w1, w2, w3, z, u, v; S_RGBA col1, col2, col3, color; IZG_ASSERT(pRenderer && v1 && v2 && v3 && n1 && n2 && n3); /* vypocet barev ve vrcholech */ col1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1); col2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2); col3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3); /* obalka trojuhleniku */ minx = MIN(x1, MIN(x2, x3)); maxx = MAX(x1, MAX(x2, x3)); miny = MIN(y1, MIN(y2, y3)); maxy = MAX(y1, MAX(y2, y3)); /* oriznuti podle rozmeru okna */ miny = MAX(miny, 0); maxy = MIN(maxy, pRenderer->frame_h - 1); minx = MAX(minx, 0); maxx = MIN(maxx, pRenderer->frame_w - 1); /* Pineduv alg. rasterizace troj. hranova fce je obecna rovnice primky Ax + By + C = 0 primku prochazejici body (x1, y1) a (x2, y2) urcime jako (y1 - y2)x + (x2 - x1)y + x1y2 - x2y1 = 0 */ /* normala primek - vektor kolmy k vektoru mezi dvema vrcholy, tedy (-dy, dx) */ a1 = y1 - y2; a2 = y2 - y3; a3 = y3 - y1; b1 = x2 - x1; b2 = x3 - x2; b3 = x1 - x3; /* koeficient C */ c1 = x1 * y2 - x2 * y1; c2 = x2 * y3 - x3 * y2; c3 = x3 * y1 - x1 * y3; /* vypocet hranove fce (vzdalenost od primky) pro protejsi body */ s1 = a1 * x3 + b1 * y3 + c1; s2 = a2 * x1 + b2 * y1 + c2; s3 = a3 * x2 + b3 * y2 + c3; if ( !s1 || !s2 || !s3 ) { return; } /* normalizace, aby vzdalenost od primky byla kladna uvnitr trojuhelniku */ if( s1 < 0 ) { a1 *= -1; b1 *= -1; c1 *= -1; } if( s2 < 0 ) { a2 *= -1; b2 *= -1; c2 *= -1; } if( s3 < 0 ) { a3 *= -1; b3 *= -1; c3 *= -1; } /* koeficienty pro barycentricke souradnice */ alpha = 1.0 / ABS(s2); beta = 1.0 / ABS(s3); gamma = 1.0 / ABS(s1); S_RGBA newColor; /* vyplnovani... */ for( y = miny; y <= maxy; ++y ) { /* inicilizace hranove fce v bode (minx, y) */ e1 = a1 * minx + b1 * y + c1; e2 = a2 * minx + b2 * y + c2; e3 = a3 * minx + b3 * y + c3; for( x = minx; x <= maxx; ++x ) { if( e1 >= 0 && e2 >= 0 && e3 >= 0 ) { /* interpolace pomoci barycentrickych souradnic e1, e2, e3 je aktualni vzdalenost bodu (x, y) od primek */ w1 = alpha * e2; w2 = beta * e3; w3 = gamma * e1; /* interpolace z-souradnice */ z = w1 * v1->z + w2 * v2->z + w3 * v3->z; double jmenovatel = w1 / h1 + w2 / h2 + w3 / h3; u = (w1 * t0->x / h1) + (w2 * t1->x / h2) + (w3 * t2->x / h3); v = (w1 * t0->y / h1) + (w2 * t1->y / h2) + (w3 * t2->y / h3); u = u / jmenovatel; v = v / jmenovatel; newColor = studrenTextureValue((S_StudentRenderer *)pRenderer, u, v); /* interpolace barvy */ color.red = ROUND2BYTE(w1 * col1.red + w2 * col2.red + w3 * col3.red) * (newColor.red / 255.0); color.green = ROUND2BYTE(w1 * col1.green + w2 * col2.green + w3 * col3.green) * (newColor.green / 255.0); color.blue = ROUND2BYTE(w1 * col1.blue + w2 * col2.blue + w3 * col3.blue) * (newColor.blue / 255.0); color.alpha = 255; /* vykresleni bodu */ if( z < DEPTH(pRenderer, x, y) ) { PIXEL(pRenderer, x, y) = color; DEPTH(pRenderer, x, y) = z; } } /* hranova fce o pixel vedle */ e1 += a1; e2 += a2; e3 += a3; } } }
void studrenDrawTriangle(S_Renderer *pRenderer, S_Coords *v1, S_Coords *v2, S_Coords *v3, S_Coords *n1, S_Coords *n2, S_Coords *n3, int x1, int y1, int x2, int y2, int x3, int y3 ) { // oblast trojuhelniku int min[2] = { MIN(x1, MIN(x2, x3)), MIN(y1, MIN(y2, y3)) }; int max[2] = { MAX(x1, MAX(x2, x3)), MAX(y1, MAX(y2, y3)) }; // oriznuti rozmerem okna min[0] = MAX(min[0], 0); min[1] = MAX(min[1], 0); max[0] = MIN(max[0], pRenderer->frame_w - 1); max[1] = MIN(max[1], pRenderer->frame_h - 1); // pro urceni hranic trojuhelnika pouzijeme pineduv algoritmus // hranova funkce je rovnice Ax + By + C = 0 // A,B je normalovy vektor primky, tzn. (-dy, dx) // C vyjadrime jako x1y2 - x2y1 int A[3] = { { y1 - y2 }, { y2 - y3 }, { y3 - y1 } }; int B[3] = { { x2 - x1 }, { x3 - x2 }, { x1 - x3 } }; int C[3] = { { x1 * y2 - x2 * y1 }, { x2 * y3 - x3 * y2 }, { x3 * y1 - x1 * y3 } }; // do hranove funkce dosadime protejsi vrcholy // provedeme normalizaci, aby kladna strana byla uvnitr oblasti int s0 = A[0] * x3 + B[0] * y3 + C[0]; int s1 = A[1] * x1 + B[1] * y1 + C[1]; int s2 = A[2] * x2 + B[2] * y2 + C[2]; if (s0 < 0) { A[0] *= -1; B[0] *= -1; C[0] *= -1; s0 *= -1; } if (s1 < 0) { A[1] *= -1; B[1] *= -1; C[1] *= -1; s1 *= -1; } if (s2 < 0) { A[2] *= -1; B[2] *= -1; C[2] *= -1; s2 *= -1; } double _s0 = 1.0f / (double)s0; double _s1 = 1.0f / (double)s1; double _s2 = 1.0f / (double)s2; /* gourandovo stinovani */ //S_RGBA color, b1, b2, b3; //b1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1); //b2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2); //b3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3); // vyplnovani pinedovim algoritmem for (int y = min[1]; y <= max[1]; ++y) { int e[3] = { A[0] * min[0] + B[0] * y + C[0], A[1] * min[0] + B[1] * y + C[1], A[2] * min[0] + B[2] * y + C[2] }; for (int x = min[0]; x <= max[0]; ++x) { // uvnitr trojuhelniku jsou cisla kladna if (e[0] >= 0 && e[1] >= 0 && e[2] >= 0) { // spocitame barycentricke koeficienty u,v,w double u = e[1] * _s1; double v = e[2] * _s2; double w = e[0] * _s0; // nemelo by nastat, protoze jsme uvnitr trojuhelniku //if (u < 0.0f || u > 1.0f) continue; //if (v < 0.0f || v > 1.0f) continue; //if (w < 0.0f || w > 1.0f) continue; // bod v trojuhelniku pred projekci ve 3D S_Coords pt = makeCoords( u * v1->x + v * v2->x + w * v3->x, u * v1->y + v * v2->y + w * v3->y, u * v1->z + v * v2->z + w * v3->z); /* gourandovo stinovani */ //double r = u * b1.red + v * b2.red + w * b3.red; //double g = u * b1.green + v * b2.green + w * b3.green; //double b = u * b1.blue + v * b2.blue + w * b3.blue; //double a = u * b1.alpha + v * b2.alpha + w * b3.alpha; //r = MIN(255.0f, MAX(r, 0.0f)); //g = MIN(255.0f, MAX(g, 0.0f)); //b = MIN(255.0f, MAX(b, 0.0f)); //a = MIN(255.0f, MAX(a, 0.0f)); //color.red = ROUND2BYTE(r); //color.green = ROUND2BYTE(g); //color.blue = ROUND2BYTE(b); //color.alpha = ROUND2BYTE(a); // vektor smerujici od bodu ke kamere S_Coords P_Cam = makeCoords( -pt.x, -pt.y, -pRenderer->camera_dist - pt.z); // vykreslime jen blizsi body double depth = sqrt(P_Cam.x * P_Cam.x + P_Cam.y * P_Cam.y + P_Cam.z * P_Cam.z); if (depth <= DEPTH(pRenderer, x, y)) { // normala bodu S_Coords n = makeCoords( u * n1->x + v * n2->x + w * n3->x, u * n1->y + v * n2->y + w * n3->y, u * n1->z + v * n2->z + w * n3->z); coordsNormalize(&n); S_RGBA color; color = pRenderer->calcReflectanceFunc(pRenderer, &pt, &n); /* vybarvi objekt normalou */ //color.red = ROUND2BYTE(255.0f * (n.x / 2.0f + 0.5f)); //color.green = ROUND2BYTE(255.0f * (n.y / 2.0f + 0.5f)); //color.blue = ROUND2BYTE(255.0f * (-n.z / 2.0f + 0.5f)); //color.alpha = 255; DEPTH(pRenderer, x, y) = depth; PIXEL(pRenderer, x, y) = color; } } // Ei(x+1,y) = Ei(x,y) + dy e[0] += A[0]; e[1] += A[1]; e[2] += A[2]; } } }