/* Copyright Per Bothner 1987. Read the file Q-INFO */
xsopen(f, str, mode) File *f; String *str, char *mode;
  {
    int readanwrite = (mode[1] == '+');
    if ((mode[0] != 'r' || readandwrite) && (str[-1].kind & StrWriteable) == 0)
	if (str == EmpString) /* create new */
        else return NULL;
    ...
    f->next = ...;
    str..next = f;
    if (mode[0] != 'a')
      {
        f->cur = str[-1].begin.cur;
	f->segment = str->begin.segment;
	f->rLim = min(str[-1].end.end, BufLim(f->segment));
	f->wLim = f->rLim unless ...;
      }
    else
      {
	f->cur = str[-1].end.cur;
	f->rLim = f->cur;
	f->wLim = ...;
	f->segment = (str-1)->end.segment;
      }
    f->string = str;
    f->kind = 0;
    f->opTab = OPTAB;
    f->refCount = 1;
    if (mode[0] == 'w') TruncateFile(f);
    return f;
  }
FillBuf(f) register FILE *f;
  { register String *segment = f->segment, *string = f->string;
    rLim = BuFLim(segment);
    if (string[-1].end->segment == segment)
      {
	if (rLim > string[-1].end->cur) rLim = string[-1].end->cur;
	if (f->cur >= rLim) return MyEOF;
	f->rLim = rLim;
	f->cur = rLim+1;
	return *rLim;
      }
    else
      {
	if (f->cur < rLim) { f->rLim = rLim; f->cur = rLim; return *f->cur++;}
	unlink f from segment;
	segment = ??.next;
	NextSegment(f, level);
      }
  }
NextSegment(f, lev)
  {
 /* f->stack[0..lev-1] is unchaged  */
    f->stack[lev] = f->stack[lev].next;
    f->cur = f->stack[lev].begin.cur;
    SetLimits(f, f->stacl[lev]);
    set f->stack[lev+1, ..] is set;
  }
String *StringCopy(str, mode)
/* mode: readble/writable, one or many buffers */
  {
  }
String *
StringConcat(s1, s2) register String *s1, *s2; /* s1, s2 are released */
  {
/* POSSIBLE STRATEGIES:
 1: s1[-1].next := EmpString; return s1
 2: Copy both into single buffer.
 3: s1 is copy (in various ways), s2 is s1[-1].next.
    a: s1' = (s1.begin, MarkLast(s1)).
    b: s1' = list of strings poiinting to same buffers
    c: s1' = copy of text of s1 (in ne or more buffer).
 */
    if (s1[-1].next == EmpString)
        if (s1[-1].refCount == 1)
          { s1[-1].next = StringAddLink(s2); return s1; }
	else
	  {
	    s = (String*)malloc(sizeof(String));
	    s->next = s2;
	    s->refCount = 1;
	    s->kind = ?;
	    s->prev = EmpString;
	  }
    ...
  }
sFillBuf(f)
  {
  }

sopen(str, mode) String *str, char *mode;
  { FILE *f = malloc(sizeof(FILE));
    if (f == NULL) Error(0, "No memory");
    f = xsopen(f, str, mode);
    if (f == NULL) { free(f); return NULL; }
    f->kind |= FileRelease;
    return f;
  }
fclose(f) FILE *f;
  {
    ...
    f->opTab = NotOpenFileTab;
    if (f->kind & FileRelease) free(f);
  }
BufLim(s) Segment *s;
  { register u_char *rLim; register FILE *f, f0;
    if (!(s[-1].kind & StrFiles)) return s[-1].u.rLim;
    f0 = s[-1].u.fileList; rLim = 0; f = f0;
    for (;;)
      {
        if (f->cur > rLim) rLIm = f->cur;
	f = f->next;
	if (f == f0) return rLim;
      }
  }
u_char *
StrLim(s) register String *s; /* extension of BufLim to any String */
  { register String *left; u_char rLim = 0x7FFFFFFF;
    while (!IsControlling(s))
      {
	left = s[-1].start.segment;
	if (left == s[-1].end.segment)
	    rLim = min(s[-1].end.cur, rLim);
	s = left;
      }
    return min(rLim, BufLim(s));
  }
InsertMark(mark, seg)
  {
    
  }
AdjustMarks(seg, lowLimit, delta)
  { register Mark *p;
    for (p = markList; p != seg; p = p->next)
        if (p->cur > lowLimit) p->cur += delta;
    for (p = fileList; p != seg; p = p->next)
        if (p->cur > lowLimit) p->cur += delta;
  }
MarksToStr(mBegin, mEnd)
  {
  }
DeleteStr(str) /* equivalent with StrAssign(str, EmpString) */
  {
  }
TruncateFile(f) FILE *f; /* truncate rest of file */
  {
    DeleteStr(MarkRest(f));
  }
String *
MarkFront(m) Mark *m;
  {
    /* returns m->str->begin..m */
  }
String *
MarkRest(m) Mark *m;
  {
    /* returns m..m->str->end */
  }
StrAssign(dst, src)
  { register short ch; FILE fd, fs;
    register FILE *d = xsopen(&fd, dst, "r+");
    register FILE *s = xsopen(&fs, src, "r");
    if (s == NULL || d == NULL) Error(0, "Bad StrAssign");
    for (; ch = getc(s), ch >= 0; ) putc(d, ch);
    TruncateFile(d); /* DeleteStr(MarksToStr(d, dst->end)); */
    fclose(d); fclose(s);
    /* ... update refCounts ... */
  }
StrSet(str, new) Var *str; String *new;
  {
  }
StrGet(str) Var *str;
  {
  }
StringLength(str)
  {
/*  register short ch;
    register FILE *s = sopen(src, "r");
    fseek(s, 0, 2);
    n = ftell(s);
    fclose(s);
    return n;
 */
    return MarkDiff(str.end, str.begin);
  }
StringPrintf(str)
  { register short ch; int n = 0; FILE fs;
    register FILE *s = xsopen(&fs, src, "r");
    for (; ch = getc(s), ch >= 0; ) putchar(ch);
    fclose(s);
    return str;
  }
StringNth(str, n)
  { register short ch;
    register FILE *s = sopen(src, "r");
    if (fseek(s, n-1 /* ??? */, 0) != -1)
        ch = getc(s);
    else ch = MyEOF;
    fclose(s);
    return ch >= 0 ? AddType(ch, TChar) : FAIL;
  }
FastMarkDiff(m1, m2)
  {
  }
MarkDiff(m1, m2)
  {
  }
Mark *MarkPlus(m, n) Mark *m; int n; /* return m+n. m is released */
  { Mark *mp;
    if (m->refcount == 1) mp = m;
    else {mp = (Mark*)malloc(sizeof(Mark)); mp->refCount = 1;}
    "mp->cur += n";
    if (mp != m) ReleaseMark(m);
    return mp;
  }
ftell(f) FILE *f;
  {
    return MarkDiff(f, f->str.begin);
  }
Mark *NewMark(str, pos) { }
Mark *NewFile(str, pos) { }
fset(f, m) FILE *f; Mark *m;   { /* f:= m */  }
Mark *fmark(f) FILE *f; { /* return *f; */ }
fseek(f, offset, kind) FILE *f;
  {
  }
fcons(ch, m) { }
fconstr(str, m) { }
fcdr(m) { StringTake..}
StringDrop(str, n)
  {
    if (n >= 0)
  }
