#include "univ.h" Selection Selected; static int activecycles; Pad Sentinel = { {0, 0, 0, 0}, &Sentinel, &Sentinel }; PadLine *LineiToPadLine(p, line) Pad *p; int line; { register PadLine *l, *last; last = &p->sentinel; l = last->down; for( ; l != last; l = l->down) if (l->windowline == line) return l; return (PadLine *)0; } PadLine *InsAbove(l, t) register PadLine *l; register PadLine *t; { register PadLine *n; n = salloc(PadLine); *n = *t; GCString(&n->text, t->text); n->down = l; n->up = l->up; l->up->down = n; l->up = n; return n; } PadLine *InsPos(p, tk) register Pad *p; register PadLine *tk; { register PadLine *l = &p->sentinel; assert(p && tk); if ((p->po.attributes & SORTED) && tk->text) { while (ISLINE(l->up, p) && !dictorder(l->up->text, tk->text)) l = l->up; } else { while (ISLINE(l->up, p) && l->up->key > tk->key) l = l->up; } return l; } PadDeleteLine(p, l) Pad *p; PadLine *l; { register PadLine *lr, *last; if (p->haswindow) { last = &p->sentinel; for (lr = l->down; lr != last; lr = lr->down) lr->windowline--; WindowDeleteLine(p, l->windowline); if (LineShell != (Widget)NULL) LineMenuDelete(&l->po); last->windowline--; } LineDelete(l); } PadReplaceLine(p, new, old) Pad *p; register PadLine *new, *old; { old->po = new->po; if (strcmp(old->text, new->text)) { gcfree(old->text); GCString(&old->text, new->text); if (p->haswindow) WindowReplaceLine(p, old->windowline, old->text); } if (new->po.attributes & (SELECTLINE|SELECTLINET)) Select(old, p, new->po.attributes); } PadInsertLine(p, l) Pad *p; register PadLine *l; { PadLine *inspos, *last, *n; inspos = InsPos(p, l); n = l = InsAbove(inspos, l); if (p->haswindow) { l->windowline = inspos->windowline; WindowInsertLine(p, l->windowline, l->text); last = &p->sentinel; for (l = l->down; l != last; l = l->down) l->windowline++; last->windowline++; } if (n->po.attributes & (SELECTLINE|SELECTLINET)) Select(n, p, n->po.attributes); } LineDelete(l) register PadLine *l; { l->down->up = l->up; l->up->down = l->down; gcfree(l->text); free(l); } PadDummyLines(p, start, end) Pad *p; int start, end; { register int i; PadLine fake; i = start; if (!i) i = 1; fake.po.carte = 0; fake.po.attributes = FAKELINE; fake.text = ""; if (p->haswindow) WindowUpdate(p, 0); for( ; i <= end; i++) { fake.key = i; PadInsertLine(p, &fake); } if (p->haswindow) WindowUpdate(p, 1); } CreateLine(p) register Pad *p; { register long lo, hi, k; register PadLine *l; PadLine fake; lo = RcvLong(); hi = RcvLong(); if (p->sentinel.key || p->po.attributes & SORTED) return; fake.po.carte = 0; fake.po.attributes = FAKELINE; fake.text = ""; for (k = lo; k <= hi; ++k) if (k) { fake.key = k; for (l = p->sentinel.up; ISLINE(l, p); l = l->up) { if (l->key == fake.key) { PadReplaceLine(p, &fake, l); break; } } if (!ISLINE(l, p)) PadInsertLine(p, &fake); p->po.attributes |= FAKELINE; } if (lo == hi && p->haswindow && (l = p->sentinel.up)->key == lo) WindowShowLine(p, l->windowline); } PutLine(p,op) register Pad *p; Protocol op; { static PadLine prevrcvd; PadLine rcvd; char text[256]; register PadLine *l; rcvd = prevrcvd; rcvd.po.object = RcvLong(); rcvd.po.oid = RcvShort(); if (op == P_NEXTLINE) rcvd.key = ++prevrcvd.key; else { rcvd.key = RcvLong(); rcvd.po.carte = RcvLong(); rcvd.po.attributes = RcvShort(); prevrcvd = rcvd; } RcvString(rcvd.text = text); if (!p || (p->sentinel.key && rcvd.key > p->sentinel.key)) return; for (l = p->sentinel.up; ISLINE(l, p); l = l->up) { if (l->key == rcvd.key) { PadReplaceLine(p, &rcvd, l); return; } } PadInsertLine(p, &rcvd); } Linkin(p) register Pad *p; { p->back = Sentinel.back; p->back->front = p; p->front = &Sentinel; Sentinel.back = p; } Unlink(p) register Pad *p; { p->back->front = p->front; p->front->back = p->back; p->front = p->back = 0; } char NewString[] = ""; void P_Define(p, o) register Pad *p; long o; { short oid = RcvShort(); if (!p || oid != p->po.oid) { p = salloc(Pad); /* zeros */ p->sentinel.up = p->sentinel.down = &p->sentinel; Linkin(p); p->po.object = o; p->po.oid = oid; p->name = NewString; p->sentinel.text = NewString; p->tabs = 8; AddNameMenuEntry(p); } } void P_Carte(p) register Pad *p; { Index i = RcvLong(); if (p && p->po.object) { p->po.carte = i; if (p->haswindow) WindowChangeMenu(p); } } void P_HelpCarte(p) register Pad *p; { Index i = RcvLong(); if (p && p->po.object) p->helpcarte = i; } void P_Lines(p) register Pad *p; { register long k = RcvLong(); int old; if (p) { old = p->sentinel.key; if (k == old) return; if (k < old) { PadCleanup(p); old = 0; } p->sentinel.key = k; PadDummyLines(p, old + 1, k); } } void P_Banner(p) register Pad *p; { char b[256]; RcvString(b); if (p) { if (p->sentinel.text != NewString) gcfree(p->sentinel.text); GCString(&p->sentinel.text, b); if (p->haswindow) XtVaSetValues(p->pane, XtNtitle, p->sentinel.text,NULL); } } void P_Name(p) register Pad *p; { char n[256]; RcvString(n); if (p) { if (p->name != NewString) gcfree(p->name); GCString(&p->name, n); ChangeNameMenuEntry(p); } } void P_Attributes(p) register Pad *p; { register Attrib a = RcvShort(); if (p) p->po.attributes = a; } void P_Tabs(p) register Pad *p; { register short t = RcvShort(); if (p && t>0 && t<128) p->tabs = t; } void P_RemoveLine(p) register Pad *p; { register long k = RcvLong(); register PadLine *l; if (!p) return; for (l = p->sentinel.up; ISLINE(l,p); l = l->up) { if (l->key == k) { PadDeleteLine(p, l); return; } } } Pad *ObjToPad(o) register long o; { register Pad *p; for (p = Sentinel.back; ISPAD(p); p = p->back) if (p->po.object == o) return p; return 0; } Cycle() { register Pad *p; for (p = Sentinel.back; ISPAD(p); p = p->back) if (p->ticks > 0 && --p->ticks == 0) { activecycles--; ToHost(P_CYCLE, 0, &p->po, &p->po); } if (activecycles) timerstart(); } MakeGap(p) Pad *p; { register PadLine *l, *lsent = &p->sentinel; register long k = RcvLong(); register long gap = RcvLong(); for (l = lsent->down; l != lsent; l = l->down) if (l->key >= k) l->key += gap; } PadOp(op) Protocol op; { static long LINEobj; register long obj; register Pad *p; register short t; obj = op == P_NEXTLINE ? LINEobj : RcvLong(); p = ObjToPad(obj); switch ((int)op) { case P_PADDEF: P_Define(p,obj); break; case P_ATTRIBUTE: P_Attributes(p); break; case P_REMOVELINE: P_RemoveLine(p); break; case P_TABS: P_Tabs(p); break; case P_BANNER: P_Banner(p); break; case P_CARTE: P_Carte(p); break; case P_HELPCARTE: P_HelpCarte(p); break; case P_LINES: P_Lines(p); break; case P_NAME: P_Name(p); break; case P_CLEAR: PadClear(p); break; case P_MAKECURRENT: MakeCurrent(p); break; case P_LINE: LINEobj = obj; case P_NEXTLINE: PutLine(p,op); break; case P_CREATELINE: CreateLine(p); break; case P_DELETE: if (p) p->po.attributes |= USERCLOSE; DeletePad(p); break; case P_MAKEGAP: MakeGap(p); break; case P_ALARM: t = RcvShort(); if (p) { if (!p->ticks) { if (t && !activecycles) timerstart(); activecycles++; } if (!(p->ticks = t)) { activecycles--; ToHost(P_CYCLE, 0, &p->po, &p->po); } } break; default: ProtoErr("PadOp()"); } } PickOp() { PickaPad(RcvLong()); } PickedPad(p, i) Pad *p; Index i; { MakeCurrent(p); PutRemote(P_PICK); ToHost(P_ACTION, i, &p->po, &p->po); } PadClear(p) register Pad *p; { register PadLine *l, *last; PadLine fake; if (!p) return; if (p->sentinel.key) { last = &p->sentinel; fake.po.carte = 0; fake.po.attributes = FAKELINE; fake.text = ""; if (p->haswindow) WindowUpdate(p, 0); for (l = last->down; l != last; l = l->down) { if (!(l->po.attributes & FAKELINE)) PadReplaceLine(p, &fake, l); } if (p->haswindow) WindowUpdate(p, 1); } else PadCleanup(p); } PadCleanup(p) register Pad *p; { if (p->haswindow) { WindowClear(p); p->sentinel.windowline = 0; } while (ISLINE(p->sentinel.up, p)) LineDelete(p->sentinel.up); p->sentinel.key = 0; } DeletePad(p) register Pad *p; { register PadLine *l, *lu; if (!p) return; if (p->ticks) { p->ticks = 0; activecycles--; } if (p->po.attributes & USERCLOSE) { ToHost(P_USERCLOSE, 0, &p->po, &p->po); if (p->po.attributes & DONT_CLOSE) return; DeleteNameMenuEntry(p); if (p->haswindow) { WindowDestroy(p); p->haswindow = 0; } PadCleanup(p); Unlink(p); if (p->sentinel.text != NewString) gcfree(p->sentinel.text); if (p->name != NewString) gcfree(p->name); free(p); } else { if (p->haswindow) { WindowDestroy(p); p->haswindow = 0; p->sentinel.windowline = 0; } if (p->po.attributes & DONT_CLOSE) return; if (!p->sentinel.key) for (l = p->sentinel.up; ISLINE(l,p); l = lu) { lu = l->up; if (!(l->po.attributes & DONT_CUT)) PadDeleteLine(p, l); } } if (Selected.pad == p) ChangeSelection((Pad *)0, -1, (PadLine *)0); } Select(l, p, a) register PadLine *l; register Pad *p; Attrib a; { if (p && l && p->haswindow) { XRaiseWindow(XtDisplay(p->pane), XtWindow(p->pane)); WindowSelectLine(p, l->windowline, a); ChangeSelection(p, l->windowline, l); } } ChangeSelection(p, line, l) Pad *p; int line; PadLine *l; { if (p == Selected.pad && line == Selected.lineno) return; if (p) { if (!l) l = LineiToPadLine(p, line); if (!l || !(l->po.attributes&ACCEPT_KBD)) { line = -1; if (line == Selected.lineno && p == Selected.pad) return; l = (PadLine *)0; } } Selected.pad = p; Selected.line = l; Selected.lineno = line; UpdateKeyLabels(p, line); } MakeCurrent(p) register Pad *p; { register PadLine *l; if (!p) return; if (p->haswindow) { XRaiseWindow(XtDisplay(p->pane), XtWindow(p->pane)); } else { WindowCreate(p); p->haswindow = 1; } } KeySendString(s) char *s; { PadLine *l, *lsent; if (!Selected.pad) { KeyWindowMessage("No window is currently selected\n"); return; } if (s[0] == '>') { PutRemote(P_SHELL); SendLong(0L); SendShort(0); SendLong(0L); SendShort(0); SendString(s+1); if (Selected.line) { SendLong(1L); SendString(Selected.line->text); } else { lsent = &Selected.pad->sentinel; SendLong(lsent->windowline); for (l = lsent->down; l != lsent; l = l->down) SendString(l->text); } } else if (Selected.line) { PutRemote(P_KBDSTR); SendLong(Selected.pad->po.object); SendShort(Selected.pad->po.oid); SendLong(Selected.line->po.object); SendShort(Selected.line->po.oid); SendString(s); } else if (Selected.pad->po.attributes & ACCEPT_KBD) { PutRemote(P_KBDSTR); SendLong(Selected.pad->po.object); SendShort(Selected.pad->po.oid); SendLong(Selected.pad->po.object); SendShort(Selected.pad->po.oid); SendString(s); } else { KeyWindowMessage("Window does not accept keyboard input\n"); } FlushRemote(); return; } CutLines(p, first, last) Pad *p; int first, last; { PadLine *l, *next; PadLine fake; int cnt; cnt = last - first + 1; l = LineiToPadLine(p, last); if (!l) return; WindowUpdate(p, 0); for (; cnt--; l = next) { next = l->up; if (l->po.attributes & USERCUT) ToHost(P_USERCUT, 0, &p->po, &l->po); if (!(l->po.attributes & DONT_CUT)) { if (Selected.line == l) ChangeSelection(p, -1, (PadLine *)0); if (p->sentinel.key) { fake.po.carte = 0; fake.po.attributes = FAKELINE; fake.text = ""; PadReplaceLine(p, &fake, l); } else PadDeleteLine(p, l); } } WindowUpdate(p, 1); }