implement Reader; include "sys.m"; sys: Sys;include "draw.m"; draw: Draw; Image, Point, Rect: import draw;include "tk.m"; tk: Tk;include "wmlib.m"; wmlib: Wmlib;include "string.m"; str: String;include "imagefile.m";include "xml.m"; xml: Xml; Attributes, Locator, Parser, Item: import xml;include "strmap.m"; strmap: Strmap; Map: import strmap;include "hash.m";include "bufio.m"; bufio: Bufio; Iobuf: import bufio;include "mimeimage.m"; mimeimage: Mimeimage;include "cssparser.m"; cssparser: CSSparser;include "cssfont.m"; cssfont: CSSfont;include "stylesheet.m"; stylesheet: Stylesheet; Style, Sheet: import stylesheet;include "table.m"; table: Table;include "url.m"; url: Url; ParsedUrl: import url;include "units.m"; units: Units;include "reader.m"; # TO DO:# - image links.# - client-side image maps# - subscript, superscript (which css attributes do they correspond to?)# - limit the size of the image cache. stderr: ref Sys->FD;maxblockid := 0; # assume that increments of this are atomic OEBpkgtype: con "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd";OEBdoctype: con "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd";OEBpkg, OEBdoc: con iota;Laxchecking: con 1; RULE: con 'r';TABLE: con 'b';TEXT: con 't';IMAGE: con 'i';MARK: con 'm';VSPACE: con 'v'; INDENT: con 20; Sbackground_color,Sborder, # none, solid, dotted, dashed, double, groove, ridge, inset, outset, [thin, medium, thick, <abs size>]#Sclear, # none, left, right, bothScolor,#Sdisplay, # block, inline, none, oeb-page-head, oeb-page-foot#Sfloat, # left, right, noneSfont_family, # serif, sans-serif, monospaceSfont_size, # xx-small...xx-large, smaller, larger, <abs size>Sfont_style, # normal, italicSfont_weight, # normal, boldSheight,Sline_height, # normal, <number>, <length>Slist_style_type, # decimal, lower-roman, upper-roman, lower-alpha, upper-alpha, noneSmargin_bottom,Smargin_top,Smargin_left,Smargin_right,# Soeb_column_number, # auto, 1# Spage_break_before, # auto, always, left, right# Spage_break_inside, # auto, avoidStext_align, # left, right, center, justifyStext_decoration, # none, underline, line-throughStext_indent,Svertical_align, # top, middle, bottomSwidth,Snumstyles: con iota; stylenames := array[] of { Sbackground_color => "background-color", Sborder => "border",# Sclear => "clear", Scolor => "color",# Sdisplay => "display",# Sfloat => "float", Sfont_family => "font-family", Sfont_size => "font-size", Sfont_style => "font-style", Sfont_weight => "font-weight", Sheight => "height", Sline_height => "line-height", Slist_style_type => "list-style-type", Smargin_bottom => "margin-bottom", Smargin_left => "margin-left", Smargin_right => "margin-right", Smargin_top => "margin-top",# Soeb_column_number => "oeb-column-number",# Spage_break_before => "page-break-before",# Spage_break_inside => "page-break-inside", Stext_align => "text-align", Stext_decoration => "text-decoration", Stext_indent => "text-indent", Svertical_align => "vertical-align", Swidth => "width",}; # constants for %flow elementsEa, Eb, Ebig, Eblockquote, Ebr, Ecenter, Ecite, Ecode, Edfn,Ediv, Edl, Eem, Efont, Eh1, Eh2, Eh3, Eh4, Eh5, Eh6, Ehr, Ei, Eimg,Einput, Ekbd, Elabel, Emap, Eobject, Eol, Ep, Epre, Eq, Es, Esamp,Escript, Eselect, Esmall, Espan, Estrike, Estrong, Esub, Esup, Etable,Ett, Eu, Eul, Evar, Ent, Enumflowtags: con iota; flownames := array[] of { Ea => "a", Eb => "b", Ebig => "big", Eblockquote => "blockquote", Ebr => "br", Ecenter => "center", Ecite => "cite", Ecode => "code", Edfn => "dfn", Ediv => "div", Edl => "dl", Eem => "em", Efont => "font", Eh1 => "h1", Eh2 => "h2", Eh3 => "h3", Eh4 => "h4", Eh5 => "h5", Eh6 => "h6", Ehr => "hr", Ei => "i", Eimg => "img", Einput => "input", Ekbd => "kbd", Elabel => "label", Emap => "map", Eobject => "object", Eol => "ol", Ep => "p", Epre => "pre", Eq => "q", Es => "s", Esamp => "samp", Escript => "script", Eselect => "select", Esmall => "small", Espan => "span", Estrike => "strike", Estrong => "strong", Esub => "sub", Esup => "sup", Etable => "table", Ett => "tt", Eu => "u", Eul => "ul", Evar => "var",};tagmap: ref Map; isblocklevel := array[Enumflowtags] of { * => byte 0, Eul => byte 1, Eol => byte 1, Eh1 => byte 1, Eh2 => byte 1, Eh3 => byte 1, Eh4 => byte 1, Eh5 => byte 1, Eh6 => byte 1, Epre => byte 1, Edl => byte 1, Ediv => byte 1, Ecenter => byte 1, Eblockquote => byte 1, Ehr => byte 1, Etable => byte 1, Ep => byte 1,}; inherited := array[Snumstyles] of { Scolor => byte 1, Sfont_family => byte 1, Sfont_size => byte 1, Sfont_style => byte 1, Sfont_weight => byte 1, Sline_height => byte 1, Slist_style_type => byte 1,# Soeb_column_number => byte 1,# Spage_break_before => byte 1,# Spage_break_inside => byte 1, Stext_align => byte 1, Stext_decoration => byte 1, Stext_indent => byte 1,}; defaults := array[] of { Sborder => "solid", Scolor => "black", Sfont_family => "sans-serif", Sfont_size => "medium", Sfont_weight => "normal", Sfont_style => "normal", Sheight => "normal", Sline_height => "normal", Slist_style_type => "none",# Soeb_column_number => "auto", # ?# Spage_break_before => "auto", # ? Stext_decoration => "none",}; badmodule(p: string){ sys->fprint(stderr, "reader: cannot load %s: %r\n", p); raise "fail:bad module";} init(displ: ref Draw->Display){ sys = load Sys Sys->PATH; stderr = sys->fildes(2); tk = load Tk Tk->PATH; draw = load Draw Draw->PATH; wmlib = load Wmlib Wmlib->PATH; if (wmlib == nil) badmodule(Wmlib->PATH); str = load String String->PATH; if (str == nil) badmodule(String->PATH); xml = load Xml Xml->PATH; if (xml == nil) badmodule(Xml->PATH); xml->init(); mimeimage = load Mimeimage Mimeimage->PATH; if (mimeimage == nil) badmodule(Mimeimage->PATH); mimeimage->init(displ); url = load Url Url->PATH; if (url == nil) badmodule(Url->PATH); url->init(); cssparser = load CSSparser CSSparser->PATH; if (cssparser == nil) badmodule(CSSparser->PATH); cssparser->init(); cssfont = load CSSfont CSSfont->PATH; if (cssfont == nil) badmodule(CSSfont->PATH); cssfont->init(displ); stylesheet = load Stylesheet Stylesheet->PATH; if (stylesheet == nil) badmodule(Stylesheet->PATH); stylesheet->init(stylenames); table = load Table Table->PATH; if (table == nil) badmodule(Table->PATH); table->init(); units = load Units Units->PATH; if (units == nil) badmodule(Units->PATH); units->init(); strmap = load Strmap Strmap->PATH; if (strmap == nil) badmodule(Strmap->PATH); tagmap = Map.new(flownames);} blankdatasource: Datasource; Datasource.new(f: string, fallbacks: list of (string, string), win: ref Tk->Toplevel, width: int, evch: string, warningch: chan of (Locator, string)): (ref Datasource, string){ d := ref blankdatasource; (x, e) := xml->open(f, warningch, "pre"); if (x == nil) return (nil, e); d.x = x; d.warningch = warningch; d.fallbacks = fallbacks; d.win = win; d.width = width; d.filename = f; d.evch = evch; d.stylesheet = Sheet.new(); style := d.stylesheet.newstyle(); style.attrs[0:] = defaults; d.styles = style :: nil; d.fontinfo = ref Fontinfo(nil, 0, 0) :: nil; rules := cssparser->parse(readfile("/lib/ebook/default.css")); d.stylesheet.addrules(rules, Stylesheet->DEFAULT); { if ((e = startdocument(d)) != nil) return (nil, e); d.startmark = d.mark(); return (d, nil); } exception{ "error" => return (nil, d.error); }} # make an independent copy of a datasource and rewind it to the beginning.Datasource.copy(d: self ref Datasource): ref Datasource{ newd := ref *d; (x, e) := xml->open(d.filename, d.warningch, "pre"); if (x == nil) error(d, "cannot copy " + d.filename + ": " + e); newd.x = x; newd.goto(d.startmark); return newd;} readfile(f: string): string{ if ((fd := sys->open(f, Sys->OREAD)) == nil) return nil; (ok, d) := sys->fstat(fd); if(ok < 0) return nil; if(d.length > big (128*1024)) # let's keep within bounds return nil; l := int d.length; buf := array[l] of byte; n := sys->read(fd, buf, len buf); if (n <= 0) return nil; return string buf[0:n];} error(d: ref Datasource, e: string){ d.error = sys->sprint("%s:%d: %s", d.x.loc.systemid, d.x.loc.line, e); raise "error";} warning(d: ref Datasource, e: string){ if (d.warningch != nil) d.warningch <-= (d.x.loc, e); else sys->print("(nil warningch) %s\n", e);} Datasource.next(d: self ref Datasource, linkch: chan of (string, string, string)): (Block, string){ { w := ".t" + string maxblockid++; d.t = Text.new(d.win, w, d.width, d.evch); d.t.style = hd d.styles; d.t.fontinfo = hd d.fontinfo; d.linkch = linkch; m := d.imark; if ((gi := d.item) == nil) { m = d.x.mark(); gi = nextitem(d, 1); } d.item = nil; d.imark = nil; if (gi == nil) { cmd(d.win, "destroy " + w); return ((nil, 0, 0), d.error); } first := 1; for (;;) { pick i := gi { Text => e_inline_text(d, i); Tag => tagid := tagmap.i(i.name); if (tagid == -1) { warning(d, "unknown tag '" + i.name + "'; expected %flow"); continue; } if (int isblocklevel[tagid]) { if (!first) { d.t.finalise(0); d.item = i; d.imark = m; b := Block(w, d.t.outertmargin, d.t.outerbmargin); d.t = nil; return (b, nil); } e_block(d, tagid, i); } else e_inline(d, tagid, i); } # XXX sending links when getting an item here is not correct, # as if it's a block level item with an id, then the link marker # will go at the end of the current block rather than the # beginning of the next block as it should. m = d.x.mark(); gi = nextitem(d, 1); if (gi == nil) { d.t.finalise(0); b := Block(w, d.t.outertmargin, d.t.outerbmargin); d.t = nil; return (b, nil); } first = 0; } } exception{ "error" => return ((nil, 0, 0), d.error); }} Datasource.linestart(d: self ref Datasource, w: string, y: int): int{ if (w[1] == 't') { # given a text widget and a y-coord inside it, adjust the # y-coord so it refers to the start of the line holding the y-coord. (n, toks) := sys->tokenize(cmd(d.win, w + " dlineinfo @0," + string y), " "); if (n >= 5) { # dlineinfo gives fields: x y width height baseline return int hd tl toks; } } return y;} Datasource.linkoffset(d: self ref Datasource, w: string, m: string): int{ (n, toks) := sys->tokenize(cmd(d.win, w + " dlineinfo " + m), " "); if (n >= 5) return int hd tl toks; return -1;} # return a "best-effort" file offset #Datasource.fileoffsetnearyoffset(t: self ref Datasource, w: string, yoffset: int): intDatasource.fileoffsetnearyoffset(nil: self ref Datasource, nil: string, nil: int): int{ # as we can't find out what embedded widget is at a given index, # we'll go first through all the embedded widgets checking to see which # ones are hit by the y-coord. return 0;} Datasource.rectforfileoffset(d: self ref Datasource, w: string, fileoffset: int): (int, Draw->Rect){ r := Rect((0, 0), (0, 0)); case widgettype(w) { IMAGE or MARK or RULE => return (0, r); TABLE =>#sys->print("rectforfileoffset requested for table...\n"); return (0, r); TEXT => # find greatest fileoffset in text less than fileoffset (nil, toks) := sys->tokenize(cmd(d.win, w + " tag names"), " "); max := -1; for (; toks != nil; toks = tl toks) { if ((hd toks)[0] == 'o') { o := int (hd toks)[1:]; if (o <= fileoffset && o > max) max = o; } } if (max == -1) return (0, r); idx := cmd(d.win, w + " index o" + string max + ".first"); # check whether we've hit an embedded widget. ew := tk->cmd(d.win, w + " window cget " + idx + " -window"); if (ew[0] != '!') {Lines 1–500 of 1797. Load more
implement Reader; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Image, Point, Rect: import draw; include "tk.m"; tk: Tk; include "wmlib.m"; wmlib: Wmlib; include "string.m"; str: String; include "imagefile.m"; include "xml.m"; xml: Xml; Attributes, Locator, Parser, Item: import xml; include "strmap.m"; strmap: Strmap; Map: import strmap; include "hash.m"; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "mimeimage.m"; mimeimage: Mimeimage; include "cssparser.m"; cssparser: CSSparser; include "cssfont.m"; cssfont: CSSfont; include "stylesheet.m"; stylesheet: Stylesheet; Style, Sheet: import stylesheet; include "table.m"; table: Table; include "url.m"; url: Url; ParsedUrl: import url; include "units.m"; units: Units; include "reader.m"; # TO DO: # - image links. # - client-side image maps # - subscript, superscript (which css attributes do they correspond to?) # - limit the size of the image cache. stderr: ref Sys->FD; maxblockid := 0; # assume that increments of this are atomic OEBpkgtype: con "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"; OEBdoctype: con "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"; OEBpkg, OEBdoc: con iota; Laxchecking: con 1; RULE: con 'r'; TABLE: con 'b'; TEXT: con 't'; IMAGE: con 'i'; MARK: con 'm'; VSPACE: con 'v'; INDENT: con 20; Sbackground_color, Sborder, # none, solid, dotted, dashed, double, groove, ridge, inset, outset, [thin, medium, thick, <abs size>] #Sclear, # none, left, right, both Scolor, #Sdisplay, # block, inline, none, oeb-page-head, oeb-page-foot #Sfloat, # left, right, none Sfont_family, # serif, sans-serif, monospace Sfont_size, # xx-small...xx-large, smaller, larger, <abs size> Sfont_style, # normal, italic Sfont_weight, # normal, bold Sheight, Sline_height, # normal, <number>, <length> Slist_style_type, # decimal, lower-roman, upper-roman, lower-alpha, upper-alpha, none Smargin_bottom, Smargin_top, Smargin_left, Smargin_right, # Soeb_column_number, # auto, 1 # Spage_break_before, # auto, always, left, right # Spage_break_inside, # auto, avoid Stext_align, # left, right, center, justify Stext_decoration, # none, underline, line-through Stext_indent, Svertical_align, # top, middle, bottom Swidth, Snumstyles: con iota; stylenames := array[] of { Sbackground_color => "background-color", Sborder => "border", # Sclear => "clear", Scolor => "color", # Sdisplay => "display", # Sfloat => "float", Sfont_family => "font-family", Sfont_size => "font-size", Sfont_style => "font-style", Sfont_weight => "font-weight", Sheight => "height", Sline_height => "line-height", Slist_style_type => "list-style-type", Smargin_bottom => "margin-bottom", Smargin_left => "margin-left", Smargin_right => "margin-right", Smargin_top => "margin-top", # Soeb_column_number => "oeb-column-number", # Spage_break_before => "page-break-before", # Spage_break_inside => "page-break-inside", Stext_align => "text-align", Stext_decoration => "text-decoration", Stext_indent => "text-indent", Svertical_align => "vertical-align", Swidth => "width", }; # constants for %flow elements Ea, Eb, Ebig, Eblockquote, Ebr, Ecenter, Ecite, Ecode, Edfn, Ediv, Edl, Eem, Efont, Eh1, Eh2, Eh3, Eh4, Eh5, Eh6, Ehr, Ei, Eimg, Einput, Ekbd, Elabel, Emap, Eobject, Eol, Ep, Epre, Eq, Es, Esamp, Escript, Eselect, Esmall, Espan, Estrike, Estrong, Esub, Esup, Etable, Ett, Eu, Eul, Evar, Ent, Enumflowtags: con iota; flownames := array[] of { Ea => "a", Eb => "b", Ebig => "big", Eblockquote => "blockquote", Ebr => "br", Ecenter => "center", Ecite => "cite", Ecode => "code", Edfn => "dfn", Ediv => "div", Edl => "dl", Eem => "em", Efont => "font", Eh1 => "h1", Eh2 => "h2", Eh3 => "h3", Eh4 => "h4", Eh5 => "h5", Eh6 => "h6", Ehr => "hr", Ei => "i", Eimg => "img", Einput => "input", Ekbd => "kbd", Elabel => "label", Emap => "map", Eobject => "object", Eol => "ol", Ep => "p", Epre => "pre", Eq => "q", Es => "s", Esamp => "samp", Escript => "script", Eselect => "select", Esmall => "small", Espan => "span", Estrike => "strike", Estrong => "strong", Esub => "sub", Esup => "sup", Etable => "table", Ett => "tt", Eu => "u", Eul => "ul", Evar => "var", }; tagmap: ref Map; isblocklevel := array[Enumflowtags] of { * => byte 0, Eul => byte 1, Eol => byte 1, Eh1 => byte 1, Eh2 => byte 1, Eh3 => byte 1, Eh4 => byte 1, Eh5 => byte 1, Eh6 => byte 1, Epre => byte 1, Edl => byte 1, Ediv => byte 1, Ecenter => byte 1, Eblockquote => byte 1, Ehr => byte 1, Etable => byte 1, Ep => byte 1, }; inherited := array[Snumstyles] of { Scolor => byte 1, Sfont_family => byte 1, Sfont_size => byte 1, Sfont_style => byte 1, Sfont_weight => byte 1, Sline_height => byte 1, Slist_style_type => byte 1, # Soeb_column_number => byte 1, # Spage_break_before => byte 1, # Spage_break_inside => byte 1, Stext_align => byte 1, Stext_decoration => byte 1, Stext_indent => byte 1, }; defaults := array[] of { Sborder => "solid", Scolor => "black", Sfont_family => "sans-serif", Sfont_size => "medium", Sfont_weight => "normal", Sfont_style => "normal", Sheight => "normal", Sline_height => "normal", Slist_style_type => "none", # Soeb_column_number => "auto", # ? # Spage_break_before => "auto", # ? Stext_decoration => "none", }; badmodule(p: string) { sys->fprint(stderr, "reader: cannot load %s: %r\n", p); raise "fail:bad module"; } init(displ: ref Draw->Display) { sys = load Sys Sys->PATH; stderr = sys->fildes(2); tk = load Tk Tk->PATH; draw = load Draw Draw->PATH; wmlib = load Wmlib Wmlib->PATH; if (wmlib == nil) badmodule(Wmlib->PATH); str = load String String->PATH; if (str == nil) badmodule(String->PATH); xml = load Xml Xml->PATH; if (xml == nil) badmodule(Xml->PATH); xml->init(); mimeimage = load Mimeimage Mimeimage->PATH; if (mimeimage == nil) badmodule(Mimeimage->PATH); mimeimage->init(displ); url = load Url Url->PATH; if (url == nil) badmodule(Url->PATH); url->init(); cssparser = load CSSparser CSSparser->PATH; if (cssparser == nil) badmodule(CSSparser->PATH); cssparser->init(); cssfont = load CSSfont CSSfont->PATH; if (cssfont == nil) badmodule(CSSfont->PATH); cssfont->init(displ); stylesheet = load Stylesheet Stylesheet->PATH; if (stylesheet == nil) badmodule(Stylesheet->PATH); stylesheet->init(stylenames); table = load Table Table->PATH; if (table == nil) badmodule(Table->PATH); table->init(); units = load Units Units->PATH; if (units == nil) badmodule(Units->PATH); units->init(); strmap = load Strmap Strmap->PATH; if (strmap == nil) badmodule(Strmap->PATH); tagmap = Map.new(flownames); } blankdatasource: Datasource; Datasource.new(f: string, fallbacks: list of (string, string), win: ref Tk->Toplevel, width: int, evch: string, warningch: chan of (Locator, string)): (ref Datasource, string) { d := ref blankdatasource; (x, e) := xml->open(f, warningch, "pre"); if (x == nil) return (nil, e); d.x = x; d.warningch = warningch; d.fallbacks = fallbacks; d.win = win; d.width = width; d.filename = f; d.evch = evch; d.stylesheet = Sheet.new(); style := d.stylesheet.newstyle(); style.attrs[0:] = defaults; d.styles = style :: nil; d.fontinfo = ref Fontinfo(nil, 0, 0) :: nil; rules := cssparser->parse(readfile("/lib/ebook/default.css")); d.stylesheet.addrules(rules, Stylesheet->DEFAULT); { if ((e = startdocument(d)) != nil) return (nil, e); d.startmark = d.mark(); return (d, nil); } exception{ "error" => return (nil, d.error); } } # make an independent copy of a datasource and rewind it to the beginning. Datasource.copy(d: self ref Datasource): ref Datasource { newd := ref *d; (x, e) := xml->open(d.filename, d.warningch, "pre"); if (x == nil) error(d, "cannot copy " + d.filename + ": " + e); newd.x = x; newd.goto(d.startmark); return newd; } readfile(f: string): string { if ((fd := sys->open(f, Sys->OREAD)) == nil) return nil; (ok, d) := sys->fstat(fd); if(ok < 0) return nil; if(d.length > big (128*1024)) # let's keep within bounds return nil; l := int d.length; buf := array[l] of byte; n := sys->read(fd, buf, len buf); if (n <= 0) return nil; return string buf[0:n]; } error(d: ref Datasource, e: string) { d.error = sys->sprint("%s:%d: %s", d.x.loc.systemid, d.x.loc.line, e); raise "error"; } warning(d: ref Datasource, e: string) { if (d.warningch != nil) d.warningch <-= (d.x.loc, e); else sys->print("(nil warningch) %s\n", e); } Datasource.next(d: self ref Datasource, linkch: chan of (string, string, string)): (Block, string) { { w := ".t" + string maxblockid++; d.t = Text.new(d.win, w, d.width, d.evch); d.t.style = hd d.styles; d.t.fontinfo = hd d.fontinfo; d.linkch = linkch; m := d.imark; if ((gi := d.item) == nil) { m = d.x.mark(); gi = nextitem(d, 1); } d.item = nil; d.imark = nil; if (gi == nil) { cmd(d.win, "destroy " + w); return ((nil, 0, 0), d.error); } first := 1; for (;;) { pick i := gi { Text => e_inline_text(d, i); Tag => tagid := tagmap.i(i.name); if (tagid == -1) { warning(d, "unknown tag '" + i.name + "'; expected %flow"); continue; } if (int isblocklevel[tagid]) { if (!first) { d.t.finalise(0); d.item = i; d.imark = m; b := Block(w, d.t.outertmargin, d.t.outerbmargin); d.t = nil; return (b, nil); } e_block(d, tagid, i); } else e_inline(d, tagid, i); } # XXX sending links when getting an item here is not correct, # as if it's a block level item with an id, then the link marker # will go at the end of the current block rather than the # beginning of the next block as it should. m = d.x.mark(); gi = nextitem(d, 1); if (gi == nil) { d.t.finalise(0); b := Block(w, d.t.outertmargin, d.t.outerbmargin); d.t = nil; return (b, nil); } first = 0; } } exception{ "error" => return ((nil, 0, 0), d.error); } } Datasource.linestart(d: self ref Datasource, w: string, y: int): int { if (w[1] == 't') { # given a text widget and a y-coord inside it, adjust the # y-coord so it refers to the start of the line holding the y-coord. (n, toks) := sys->tokenize(cmd(d.win, w + " dlineinfo @0," + string y), " "); if (n >= 5) { # dlineinfo gives fields: x y width height baseline return int hd tl toks; } } return y; } Datasource.linkoffset(d: self ref Datasource, w: string, m: string): int { (n, toks) := sys->tokenize(cmd(d.win, w + " dlineinfo " + m), " "); if (n >= 5) return int hd tl toks; return -1; } # return a "best-effort" file offset #Datasource.fileoffsetnearyoffset(t: self ref Datasource, w: string, yoffset: int): int Datasource.fileoffsetnearyoffset(nil: self ref Datasource, nil: string, nil: int): int { # as we can't find out what embedded widget is at a given index, # we'll go first through all the embedded widgets checking to see which # ones are hit by the y-coord. return 0; } Datasource.rectforfileoffset(d: self ref Datasource, w: string, fileoffset: int): (int, Draw->Rect) { r := Rect((0, 0), (0, 0)); case widgettype(w) { IMAGE or MARK or RULE => return (0, r); TABLE => #sys->print("rectforfileoffset requested for table...\n"); return (0, r); TEXT => # find greatest fileoffset in text less than fileoffset (nil, toks) := sys->tokenize(cmd(d.win, w + " tag names"), " "); max := -1; for (; toks != nil; toks = tl toks) { if ((hd toks)[0] == 'o') { o := int (hd toks)[1:]; if (o <= fileoffset && o > max) max = o; } } if (max == -1) return (0, r); idx := cmd(d.win, w + " index o" + string max + ".first"); # check whether we've hit an embedded widget. ew := tk->cmd(d.win, w + " window cget " + idx + " -window"); if (ew[0] != '!') {