tAdd libString. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 7f11104a5737adf261d10bc1a7b85e740f2eb491
 (DIR) parent 57ccfb9e8f51138c33ad5f58e14c0e54246cf5c4
 (HTM) Author: rsc <devnull@localhost>
       Date:   Thu, 11 Dec 2003 18:15:57 +0000
       
       Add libString.
       
       Diffstat:
         A include/html.h                      |     629 +++++++++++++++++++++++++++++++
         A include/libString.h                 |      46 +++++++++++++++++++++++++++++++
         A src/libString/mkfile                |      27 +++++++++++++++++++++++++++
         A src/libString/s_alloc.c             |      86 ++++++++++++++++++++++++++++++
         A src/libString/s_append.c            |      17 +++++++++++++++++
         A src/libString/s_array.c             |      17 +++++++++++++++++
         A src/libString/s_copy.c              |      19 +++++++++++++++++++
         A src/libString/s_getline.c           |      72 +++++++++++++++++++++++++++++++
         A src/libString/s_grow.c              |      34 +++++++++++++++++++++++++++++++
         A src/libString/s_memappend.c         |      20 ++++++++++++++++++++
         A src/libString/s_nappend.c           |      18 ++++++++++++++++++
         A src/libString/s_parse.c             |      40 +++++++++++++++++++++++++++++++
         A src/libString/s_putc.c              |      13 +++++++++++++
         A src/libString/s_rdinstack.c         |     141 +++++++++++++++++++++++++++++++
         A src/libString/s_read.c              |      38 +++++++++++++++++++++++++++++++
         A src/libString/s_read_line.c         |      31 +++++++++++++++++++++++++++++++
         A src/libString/s_reset.c             |      23 +++++++++++++++++++++++
         A src/libString/s_terminate.c         |      13 +++++++++++++
         A src/libString/s_tolower.c           |      15 +++++++++++++++
         A src/libString/s_unique.c            |      16 ++++++++++++++++
       
       20 files changed, 1315 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/include/html.h b/include/html.h
       t@@ -0,0 +1,629 @@
       +#ifndef _HTML_H_
       +#define _HTML_H_ 1
       +#ifdef __cplusplus
       +extern "C" {
       +#endif
       +
       +/*
       + #pragma lib "libhtml.a"
       + #pragma src "/sys/src/libhtml"
       +*/
       +
       +// UTILS
       +extern uchar*        fromStr(Rune* buf, int n, int chset);
       +extern Rune*        toStr(uchar* buf, int n, int chset);
       +
       +// Common LEX and BUILD enums
       +
       +// Media types
       +enum
       +{
       +        ApplMsword,
       +        ApplOctets,
       +        ApplPdf,
       +        ApplPostscript,
       +        ApplRtf,
       +        ApplFramemaker,
       +        ApplMsexcel,
       +        ApplMspowerpoint,
       +        UnknownType,
       +        Audio32kadpcm,
       +        AudioBasic,
       +        ImageCgm,
       +        ImageG3fax,
       +        ImageGif,
       +        ImageIef,
       +        ImageJpeg,
       +        ImagePng,
       +        ImageTiff,
       +        ImageXBit,
       +        ImageXBit2,
       +        ImageXBitmulti,
       +        ImageXXBitmap,
       +        ModelVrml,
       +        MultiDigest,
       +        MultiMixed,
       +        TextCss,
       +        TextEnriched,
       +        TextHtml,
       +        TextJavascript,
       +        TextPlain,
       +        TextRichtext,
       +        TextSgml,
       +        TextTabSeparatedValues,
       +        TextXml,
       +        VideoMpeg,
       +        VideoQuicktime,
       +        NMEDIATYPES
       +};
       +
       +// HTTP methods
       +enum
       +{
       +        HGet,
       +        HPost
       +};
       +
       +// Charsets
       +enum
       +{
       +        UnknownCharset,
       +        US_Ascii,
       +        ISO_8859_1,
       +        UTF_8,
       +        Unicode,
       +        NCHARSETS
       +};
       +
       +// Frame Target IDs
       +enum {
       +        FTtop,
       +        FTself,
       +        FTparent,
       +        FTblank
       +};
       +
       +// LEX
       +typedef struct Token Token;
       +typedef struct Attr Attr;
       +
       +// BUILD
       +
       +typedef struct Item Item;
       +typedef struct Itext Itext;
       +typedef struct Irule Irule;
       +typedef struct Iimage Iimage;
       +typedef struct Iformfield Iformfield;
       +typedef struct Itable Itable;
       +typedef struct Ifloat Ifloat;
       +typedef struct Ispacer Ispacer;
       +typedef struct Genattr Genattr;
       +typedef struct SEvent SEvent;
       +typedef struct Formfield Formfield;
       +typedef struct Option Option;
       +typedef struct Form Form;
       +typedef struct Table Table;
       +typedef struct Tablecol Tablecol;
       +typedef struct Tablerow Tablerow;
       +typedef struct Tablecell Tablecell;
       +typedef struct Align Align;
       +typedef struct Dimen Dimen;
       +typedef struct Anchor Anchor;
       +typedef struct DestAnchor DestAnchor;
       +typedef struct Map Map;
       +typedef struct Area Area;
       +typedef struct Background Background;
       +typedef struct Kidinfo Kidinfo;
       +typedef struct Docinfo Docinfo;
       +typedef struct Stack Stack;
       +typedef struct Pstate Pstate;
       +typedef struct ItemSource ItemSource;
       +typedef struct Lay Lay;        // defined in Layout module
       +
       +// Alignment types
       +enum {
       +        ALnone = 0, ALleft, ALcenter, ALright, ALjustify,
       +        ALchar, ALtop, ALmiddle, ALbottom, ALbaseline
       +};
       +
       +struct Align
       +{
       +        uchar        halign;        // one of ALnone, ALleft, etc.
       +        uchar        valign;        // one of ALnone, ALtop, etc.
       +};
       +
       +// A Dimen holds a dimension specification, especially for those
       +// cases when a number can be followed by a % or a * to indicate
       +// percentage of total or relative weight.
       +// Dnone means no dimension was specified
       +
       +// To fit in a word, use top bits to identify kind, rest for value
       +enum {
       +        Dnone =                0,
       +        Dpixels =                (1<<29),
       +        Dpercent =        (2<<29),
       +        Drelative =        (3<<29),
       +        Dkindmask =        (3<<29),
       +        Dspecmask =        (~Dkindmask)
       +};
       +
       +struct Dimen
       +{
       +        int        kindspec;                // kind | spec
       +};
       +
       +// Background is either an image or a color.
       +// If both are set, the image has precedence.
       +struct Background
       +{
       +        Rune*        image;        // url
       +        int                color;
       +};
       +
       +
       +// There are about a half dozen Item variants.
       +// The all look like this at the start (using Plan 9 C's
       +// anonymous structure member mechanism),
       +// and then the tag field dictates what extra fields there are.
       +struct Item
       +{
       +        Item*        next;                // successor in list of items
       +        int                width;        // width in pixels (0 for floating items)
       +        int                height;        // height in pixels
       +        int                ascent;        // ascent (from top to baseline) in pixels
       +        int                anchorid;        // if nonzero, which anchor we're in
       +        int                state;        // flags and values (see below)
       +        Genattr*        genattr;        // generic attributes and events
       +        int                tag;                // variant discriminator: Itexttag, etc.
       +};
       +
       +// Item variant tags
       +enum {
       +        Itexttag,
       +        Iruletag,
       +        Iimagetag,
       +        Iformfieldtag,
       +        Itabletag,
       +        Ifloattag,
       +        Ispacertag
       +};
       +
       +struct Itext
       +{
       +        Item _item;                                // (with tag ==Itexttag)
       +        Rune*        s;                        // the characters
       +        int                fnt;                        // style*NumSize+size (see font stuff, below)
       +        int                fg;                        // Pixel (color) for text
       +        uchar        voff;                        // Voffbias+vertical offset from baseline, in pixels (+ve == down)
       +        uchar        ul;                        // ULnone, ULunder, or ULmid
       +};
       +
       +struct Irule
       +{
       +        Item _item;                                // (with tag ==Iruletag)
       +        uchar        align;                // alignment spec
       +        uchar        noshade;                // if true, don't shade
       +        int                size;                        // size attr (rule height)
       +        Dimen        wspec;                // width spec
       +};
       +
       +
       +struct Iimage
       +{
       +        Item _item;                                // (with tag ==Iimagetag)
       +        Rune*        imsrc;                // image src url
       +        int                imwidth;                // spec width (actual, if no spec)
       +        int                imheight;                // spec height (actual, if no spec)
       +        Rune*        altrep;                // alternate representation, in absence of image
       +        Map*        map;                        // if non-nil, client side map
       +        int                ctlid;                        // if animated
       +        uchar        align;                // vertical alignment
       +        uchar        hspace;                // in pixels; buffer space on each side
       +        uchar        vspace;                // in pixels; buffer space on top and bottom
       +        uchar        border;                // in pixels: border width to draw around image
       +        Iimage*        nextimage;        // next in list of document's images
       +};
       +
       +
       +struct Iformfield
       +{
       +        Item _item;                                // (with tag ==Iformfieldtag)
       +        Formfield*        formfield;
       +};
       +
       +
       +struct Itable
       +{
       +        Item _item;                                // (with tag ==Itabletag)
       +        Table*        table;
       +};
       +
       +
       +struct Ifloat
       +{
       +        Item _item;                                // (with tag ==Ifloattag)
       +        Item*        item;                        // table or image item that floats
       +        int                x;                        // x coord of top (from right, if ALright)
       +        int                y;                        // y coord of top
       +        uchar        side;                        // margin it floats to: ALleft or ALright
       +        uchar        infloats;                // true if this has been added to a lay.floats
       +        Ifloat*        nextfloat;                // in list of floats
       +};
       +
       +
       +struct Ispacer
       +{
       +        Item _item;                                // (with tag ==Ispacertag)
       +        int                spkind;                // ISPnull, etc.
       +};
       +
       +// Item state flags and value fields
       +enum {
       +        IFbrk =                        0x80000000,        // forced break before this item
       +        IFbrksp =                        0x40000000,        // add 1 line space to break (IFbrk set too)
       +        IFnobrk =                        0x20000000,        // break not allowed before this item
       +        IFcleft =                        0x10000000,        // clear left floats (IFbrk set too)
       +        IFcright =                        0x08000000,        // clear right floats (IFbrk set too)
       +        IFwrap =                        0x04000000,        // in a wrapping (non-pre) line
       +        IFhang =                        0x02000000,        // in a hanging (into left indent) item
       +        IFrjust =                        0x01000000,        // right justify current line
       +        IFcjust =                        0x00800000,        // center justify current line
       +        IFsmap =                        0x00400000,        // image is server-side map
       +        IFindentshift =                8,
       +        IFindentmask =                (255<<IFindentshift),        // current indent, in tab stops
       +        IFhangmask =                255                        // current hang into left indent, in 1/10th tabstops
       +};
       +
       +// Bias added to Itext's voff field
       +enum { Voffbias = 128 };
       +
       +// Spacer kinds
       +enum {
       +        ISPnull,                        // 0 height and width
       +        ISPvline,                        // height and ascent of current font
       +        ISPhspace,                // width of space in current font
       +        ISPgeneral                // other purposes (e.g., between markers and list)
       +};
       +
       +// Generic attributes and events (not many elements will have any of these set)
       +struct Genattr
       +{
       +        Rune*        id;
       +        Rune*        class;
       +        Rune*        style;
       +        Rune*        title;
       +        SEvent*        events;
       +};
       +
       +struct SEvent
       +{
       +        SEvent*        next;                // in list of events
       +        int                type;                // SEonblur, etc.
       +        Rune*        script;
       +};
       +
       +enum {
       +        SEonblur, SEonchange, SEonclick, SEondblclick,
       +        SEonfocus, SEonkeypress, SEonkeyup, SEonload,
       +        SEonmousedown, SEonmousemove, SEonmouseout,
       +        SEonmouseover, SEonmouseup, SEonreset, SEonselect,
       +        SEonsubmit, SEonunload,
       +        Numscriptev
       +};
       +
       +// Form field types
       +enum {
       +        Ftext,
       +        Fpassword,
       +        Fcheckbox,
       +        Fradio,
       +        Fsubmit,
       +        Fhidden,
       +        Fimage,
       +        Freset,
       +        Ffile,
       +        Fbutton,
       +        Fselect,
       +        Ftextarea
       +};
       +
       +// Information about a field in a form
       +struct Formfield
       +{
       +        Formfield*        next;                // in list of fields for a form
       +        int                        ftype;        // Ftext, Fpassword, etc.
       +        int                        fieldid;        // serial no. of field within its form
       +        Form*                form;        // containing form
       +        Rune*                name;        // name attr
       +        Rune*                value;        // value attr
       +        int                        size;                // size attr
       +        int                        maxlength;        // maxlength attr
       +        int                        rows;        // rows attr
       +        int                        cols;                // cols attr
       +        uchar                flags;        // FFchecked, etc.
       +        Option*                options;        // for Fselect fields
       +        Item*                image;        // image item, for Fimage fields
       +        int                        ctlid;                // identifies control for this field in layout
       +        SEvent*                events;        // same as genattr->events of containing item
       +};
       +
       +enum {
       +        FFchecked =        (1<<7),
       +        FFmultiple =        (1<<6)
       +};
       +
       +// Option holds info about an option in a "select" form field
       +struct Option
       +{
       +        Option*        next;                        // next in list of options for a field
       +        int                selected;                // true if selected initially
       +        Rune*        value;                // value attr
       +        Rune*        display;                // display string
       +};
       +
       +// Form holds info about a form
       +struct Form
       +{
       +        Form*                next;                // in list of forms for document
       +        int                        formid;        // serial no. of form within its doc
       +        Rune*                name;        // name or id attr (netscape uses name, HTML 4.0 uses id)
       +        Rune*                action;        // action attr
       +        int                        target;        // target attr as targetid
       +        int                        method;        // HGet or HPost
       +        int                        nfields;        // number of fields
       +        Formfield*        fields;        // field's forms, in input order
       +};
       +
       +// Flags used in various table structures
       +enum {
       +        TFparsing =        (1<<7),
       +        TFnowrap =        (1<<6),
       +        TFisth =                (1<<5)
       +};
       +
       +
       +// Information about a table
       +struct Table
       +{
       +        Table*                next;                        // next in list of document's tables
       +        int                        tableid;                // serial no. of table within its doc
       +        Tablerow*        rows;                // array of row specs (list during parsing)
       +        int                        nrow;                // total number of rows
       +        Tablecol*                cols;                        // array of column specs
       +        int                        ncol;                        // total number of columns
       +        Tablecell*                cells;                        // list of unique cells
       +        int                        ncell;                // total number of cells
       +        Tablecell***        grid;                        // 2-D array of cells
       +        Align                align;                // alignment spec for whole table
       +        Dimen                width;                // width spec for whole table
       +        int                        border;                // border attr
       +        int                        cellspacing;        // cellspacing attr
       +        int                        cellpadding;        // cellpadding attr
       +        Background        background;        // table background
       +        Item*                caption;                // linked list of Items, giving caption
       +        uchar                caption_place;        // ALtop or ALbottom
       +        Lay*                        caption_lay;        // layout of caption
       +        int                        totw;                        // total width
       +        int                        toth;                        // total height
       +        int                        caph;                // caption height
       +        int                        availw;                // used for previous 3 sizes
       +        Token*                tabletok;                // token that started the table
       +        uchar                flags;                // Lchanged, perhaps
       +};
       +
       +
       +struct Tablecol
       +{
       +        int                width;
       +        Align        align;
       +        Point                pos;
       +};
       +
       +
       +struct Tablerow
       +{
       +        Tablerow*        next;                        // Next in list of rows, during parsing
       +        Tablecell*                cells;                        // Cells in row, linked through nextinrow
       +        int                        height;
       +        int                        ascent;
       +        Align                align;
       +        Background        background;
       +        Point                        pos;
       +        uchar                flags;                // 0 or TFparsing
       +};
       +
       +
       +// A Tablecell is one cell of a table.
       +// It may span multiple rows and multiple columns.
       +// Cells are linked on two lists: the list for all the cells of
       +// a document (the next pointers), and the list of all the
       +// cells that start in a given row (the nextinrow pointers)
       +struct Tablecell
       +{
       +        Tablecell*                next;                        // next in list of table's cells
       +        Tablecell*                nextinrow;        // next in list of row's cells
       +        int                        cellid;                // serial no. of cell within table
       +        Item*                content;                // contents before layout
       +        Lay*                        lay;                        // layout of cell
       +        int                        rowspan;                // number of rows spanned by this cell
       +        int                        colspan;                // number of cols spanned by this cell
       +        Align                align;                // alignment spec
       +        uchar                flags;                // TFparsing, TFnowrap, TFisth
       +        Dimen                wspec;                // suggested width
       +        int                        hspec;                // suggested height
       +        Background        background;        // cell background
       +        int                        minw;                // minimum possible width
       +        int                        maxw;                // maximum width
       +        int                        ascent;                // cell's ascent
       +        int                        row;                        // row of upper left corner
       +        int                        col;                        // col of upper left corner
       +        Point                        pos;                        // nw corner of cell contents, in cell
       +};
       +
       +// Anchor is for info about hyperlinks that go somewhere
       +struct Anchor
       +{
       +        Anchor*                next;                // next in list of document's anchors
       +        int                        index;        // serial no. of anchor within its doc
       +        Rune*                name;        // name attr
       +        Rune*                href;                // href attr
       +        int                        target;        // target attr as targetid
       +};
       +
       +
       +// DestAnchor is for info about hyperlinks that are destinations
       +struct DestAnchor
       +{
       +        DestAnchor*        next;                // next in list of document's destanchors
       +        int                        index;        // serial no. of anchor within its doc
       +        Rune*                name;        // name attr
       +        Item*                item;                // the destination
       +};
       +
       +
       +// Maps (client side)
       +struct Map
       +{
       +        Map*        next;                        // next in list of document's maps
       +        Rune*        name;                // map name
       +        Area*        areas;                // list of map areas
       +};
       +
       +
       +struct Area
       +{
       +        Area*                next;                // next in list of a map's areas
       +        int                        shape;        // SHrect, etc.
       +        Rune*                href;                // associated hypertext link
       +        int                        target;        // associated target frame
       +        Dimen*                coords;        // array of coords for shape
       +        int                        ncoords;        // size of coords array
       +};
       +
       +// Area shapes
       +enum {
       +        SHrect, SHcircle, SHpoly
       +};
       +
       +// Fonts are represented by integers: style*NumSize + size
       +
       +// Font styles
       +enum {
       +        FntR,                        // roman
       +        FntI,                        // italic
       +        FntB,                        // bold
       +        FntT,                        // typewriter
       +        NumStyle
       +};
       +
       +// Font sizes
       +enum {
       +        Tiny,
       +        Small,
       +        Normal,
       +        Large,
       +        Verylarge,
       +        NumSize
       +};
       +
       +enum {
       +        NumFnt = (NumStyle*NumSize),
       +        DefFnt = (FntR*NumSize+Normal)
       +};
       +
       +// Lines are needed through some text items, for underlining or strikethrough
       +enum {
       +        ULnone, ULunder, ULmid
       +};
       +
       +// Kidinfo flags
       +enum {
       +        FRnoresize =        (1<<0),
       +        FRnoscroll =        (1<<1),
       +        FRhscroll =         (1<<2),
       +        FRvscroll =        (1<<3),
       +        FRhscrollauto = (1<<4),
       +        FRvscrollauto =        (1<<5)
       +};
       +
       +// Information about child frame or frameset
       +struct Kidinfo
       +{
       +        Kidinfo*                next;                // in list of kidinfos for a frameset
       +        int                        isframeset;
       +
       +        // fields for "frame"
       +        Rune*                src;                // only nil if a "dummy" frame or this is frameset
       +        Rune*                name;        // always non-empty if this isn't frameset
       +        int                        marginw;
       +        int                        marginh;
       +        int                        framebd;
       +        int                        flags;
       +
       +        // fields for "frameset"
       +        Dimen*                rows;        // array of row dimensions
       +        int                        nrows;        // length of rows
       +        Dimen*                cols;                // array of col dimensions
       +        int                        ncols;        // length of cols
       +        Kidinfo*                kidinfos;
       +        Kidinfo*                nextframeset;        // parsing stack
       +};
       +
       +
       +// Document info (global information about HTML page)
       +struct Docinfo
       +{
       +        // stuff from HTTP headers, doc head, and body tag
       +        Rune*                src;                                // original source of doc
       +        Rune*                base;                        // base URL of doc
       +        Rune*                doctitle;                        // from <title> element
       +        Background        background;                // background specification
       +        Iimage*                backgrounditem;        // Image Item for doc background image, or nil
       +        int                        text;                                // doc foreground (text) color
       +        int                        link;                                // unvisited hyperlink color
       +        int                        vlink;                        // visited hyperlink color
       +        int                        alink;                        // highlighting hyperlink color
       +        int                        target;                        // target frame default
       +        int                        chset;                        // ISO_8859, etc.
       +        int                        mediatype;                // TextHtml, etc.
       +        int                        scripttype;                // TextJavascript, etc.
       +        int                        hasscripts;                // true if scripts used
       +        Rune*                refresh;                        // content of <http-equiv=Refresh ...>
       +        Kidinfo*                kidinfo;                        // if a frameset
       +        int                        frameid;                        // id of document frame
       +
       +        // info needed to respond to user actions
       +        Anchor*                anchors;                        // list of href anchors
       +        DestAnchor*        dests;                        // list of destination anchors
       +        Form*                forms;                        // list of forms
       +        Table*                tables;                        // list of tables
       +        Map*                maps;                        // list of maps
       +        Iimage*                images;                        // list of image items (through nextimage links)
       +};
       +
       +extern int                        dimenkind(Dimen d);
       +extern int                        dimenspec(Dimen d);
       +extern void                freedocinfo(Docinfo* d);
       +extern void                freeitems(Item* ithead);
       +extern Item*                parsehtml(uchar* data, int datalen, Rune* src, int mtype, int chset, Docinfo** pdi);
       +extern void                printitems(Item* items, char* msg);
       +extern int                        targetid(Rune* s);
       +extern Rune*                targetname(int targid);
       +extern int                        validitems(Item* i);
       +
       +#pragma varargck        type "I"        Item*
       +
       +// Control print output
       +extern int                        warn;
       +extern int                        dbglex;
       +extern int                        dbgbuild;
       +
       +// To be provided by caller
       +// emalloc and erealloc should not return if can't get memory.
       +// emalloc should zero its memory.
       +extern void*        emalloc(ulong);
       +extern void*        erealloc(void* p, ulong size);
       +#ifdef __cpluspplus
       +}
       +#endif
       +#endif
 (DIR) diff --git a/include/libString.h b/include/libString.h
       t@@ -0,0 +1,46 @@
       +/*
       +#pragma        src        "/sys/src/libString"
       +#pragma        lib        "libString.a"
       +*/
       +
       +/* extensible Strings */
       +typedef struct String {
       +        Lock        lk;
       +        char        *base;        /* base of String */
       +        char        *end;        /* end of allocated space+1 */
       +        char        *ptr;        /* ptr into String */
       +        short        ref;
       +        uchar        fixed;
       +} String;
       +
       +#define s_clone(s) s_copy((s)->base)
       +#define s_to_c(s) ((s)->base)
       +#define s_len(s) ((s)->ptr-(s)->base)
       +
       +extern String*        s_append(String*, char*);
       +extern String*        s_array(char*, int);
       +extern String*        s_copy(char*);
       +extern void        s_free(String*);
       +extern String*        s_incref(String*);        
       +extern String*        s_memappend(String*, char*, int);
       +extern String*        s_nappend(String*, char*, int);
       +extern String*        s_new(void);
       +extern String*        s_newalloc(int);
       +extern String*        s_parse(String*, String*);
       +extern String*        s_reset(String*);
       +extern String*        s_restart(String*);
       +extern void        s_terminate(String*);
       +extern void        s_tolower(String*);
       +extern void        s_putc(String*, int);
       +extern String*        s_unique(String*);
       +extern String*        s_grow(String*, int);
       +
       +#ifdef BGETC
       +extern int        s_read(Biobuf*, String*, int);
       +extern char        *s_read_line(Biobuf*, String*);
       +extern char        *s_getline(Biobuf*, String*);
       +typedef struct Sinstack Sinstack;
       +extern char        *s_rdinstack(Sinstack*, String*);
       +extern Sinstack        *s_allocinstack(char*);
       +extern void        s_freeinstack(Sinstack*);
       +#endif BGETC
 (DIR) diff --git a/src/libString/mkfile b/src/libString/mkfile
       t@@ -0,0 +1,27 @@
       +PLAN9=../..
       +<$PLAN9/src/mkhdr
       +
       +LIB=libString.a
       +
       +OFILES=\
       +        s_alloc.$O\
       +        s_append.$O\
       +        s_array.$O\
       +        s_copy.$O\
       +        s_getline.$O\
       +        s_grow.$O\
       +        s_memappend.$O\
       +        s_nappend.$O\
       +        s_parse.$O\
       +        s_putc.$O\
       +        s_rdinstack.$O\
       +        s_read.$O\
       +        s_read_line.$O\
       +        s_reset.$O\
       +        s_terminate.$O\
       +        s_tolower.$O\
       +        s_unique.$O\
       +
       +HFILES=/sys/include/String.h
       +
       +<$PLAN9/src/mksyslib
 (DIR) diff --git a/src/libString/s_alloc.c b/src/libString/s_alloc.c
       t@@ -0,0 +1,86 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +#define STRLEN 128
       +
       +extern void
       +s_free(String *sp)
       +{
       +        if (sp == nil)
       +                return;
       +        lock(&sp->lk);
       +        if(--(sp->ref) != 0){
       +                unlock(&sp->lk);
       +                return;
       +        }
       +        unlock(&sp->lk);
       +
       +        if(sp->fixed == 0 && sp->base != nil)
       +                free(sp->base);
       +        free(sp);
       +}
       +
       +/* get another reference to a string */
       +extern String *
       +s_incref(String *sp)
       +{
       +        lock(&sp->lk);
       +        sp->ref++;
       +        unlock(&sp->lk);
       +
       +        return sp;
       +}
       +
       +/* allocate a String head */
       +extern String *
       +_s_alloc(void)
       +{
       +        String *s;
       +
       +        s = mallocz(sizeof *s, 1);
       +        if(s == nil)
       +                return s;
       +        s->ref = 1;
       +        s->fixed = 0;
       +        return s;
       +}
       +
       +/* create a new `short' String */
       +extern String *
       +s_newalloc(int len)
       +{
       +        String *sp;
       +
       +        sp = _s_alloc();
       +        if(sp == nil)
       +                sysfatal("s_newalloc: %r");
       +        setmalloctag(sp, getcallerpc(&len));
       +        if(len < STRLEN)
       +                len = STRLEN;
       +        sp->base = sp->ptr = malloc(len);
       +        if (sp->base == nil)
       +                sysfatal("s_newalloc: %r");
       +        setmalloctag(sp->base, getcallerpc(&len));
       +
       +        sp->end = sp->base + len;
       +        s_terminate(sp);
       +        return sp;
       +}
       +
       +/* create a new `short' String */
       +extern String *
       +s_new(void)
       +{
       +        String *sp;
       +
       +        sp = _s_alloc();
       +        if(sp == nil)
       +                sysfatal("s_new: %r");
       +        sp->base = sp->ptr = malloc(STRLEN);
       +        if (sp->base == nil)
       +                sysfatal("s_new: %r");
       +        sp->end = sp->base + STRLEN;
       +        s_terminate(sp);
       +        return sp;
       +}
 (DIR) diff --git a/src/libString/s_append.c b/src/libString/s_append.c
       t@@ -0,0 +1,17 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +/* append a char array to a String */
       +String *
       +s_append(String *to, char *from)
       +{
       +        if (to == 0)
       +                to = s_new();
       +        if (from == 0)
       +                return to;
       +        for(; *from; from++)
       +                s_putc(to, *from);
       +        s_terminate(to);
       +        return to;
       +}
 (DIR) diff --git a/src/libString/s_array.c b/src/libString/s_array.c
       t@@ -0,0 +1,17 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +extern String*        _s_alloc(void);
       +
       +/* return a String containing a character array (this had better not grow) */
       +extern String *
       +s_array(char *cp, int len)
       +{
       +        String *sp = _s_alloc();
       +
       +        sp->base = sp->ptr = cp;
       +        sp->end = sp->base + len;
       +        sp->fixed = 1;
       +        return sp;
       +}
 (DIR) diff --git a/src/libString/s_copy.c b/src/libString/s_copy.c
       t@@ -0,0 +1,19 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +
       +/* return a String containing a copy of the passed char array */
       +extern String*
       +s_copy(char *cp)
       +{
       +        String *sp;
       +        int len;
       +
       +        len = strlen(cp)+1;
       +        sp = s_newalloc(len);
       +        setmalloctag(sp, getcallerpc(&cp));
       +        strcpy(sp->base, cp);
       +        sp->ptr = sp->base + len - 1;                /* point to 0 terminator */
       +        return sp;
       +}
 (DIR) diff --git a/src/libString/s_getline.c b/src/libString/s_getline.c
       t@@ -0,0 +1,72 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "libString.h"
       +
       +/* Append an input line to a String.
       + *
       + * Returns a pointer to the character string (or 0).
       + * Leading whitespace and newlines are removed.
       + *
       + * Empty lines and lines starting with '#' are ignored.
       + */ 
       +extern char *
       +s_getline(Biobuf *fp, String *to)
       +{
       +        int c;
       +        int len=0;
       +
       +        s_terminate(to);
       +
       +        /* end of input */
       +        if ((c = Bgetc(fp)) < 0)
       +                return 0;
       +
       +        /* take care of inconsequentials */
       +        for(;;) {
       +                /* eat leading white */
       +                while(c==' ' || c=='\t' || c=='\n' || c=='\r')
       +                        c = Bgetc(fp);
       +
       +                if(c < 0)
       +                        return 0;
       +
       +                /* take care of comments */
       +                if(c == '#'){
       +                        do {
       +                                c = Bgetc(fp);
       +                                if(c < 0)
       +                                        return 0;
       +                        } while(c != '\n');
       +                        continue;
       +                }
       +
       +                /* if we got here, we've gotten something useful */
       +                break;
       +        }
       +
       +        /* gather up a line */
       +        for(;;) {
       +                len++;
       +                switch(c) {
       +                case -1:
       +                        s_terminate(to);
       +                        return len ? to->ptr-len : 0;
       +                case '\\':
       +                        c = Bgetc(fp);
       +                        if (c != '\n') {
       +                                s_putc(to, '\\');
       +                                s_putc(to, c);
       +                        }
       +                        break;
       +                case '\n':
       +                        s_terminate(to);
       +                        return len ? to->ptr-len : 0;
       +                default:
       +                        s_putc(to, c);
       +                        break;
       +                }
       +                c = Bgetc(fp);
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/libString/s_grow.c b/src/libString/s_grow.c
       t@@ -0,0 +1,34 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +/* grow a String's allocation by at least `incr' bytes */
       +extern String*
       +s_grow(String *s, int incr)        
       +{
       +        char *cp;
       +        int size;
       +
       +        if(s->fixed)
       +                sysfatal("s_grow of constant string");
       +        s = s_unique(s);
       +
       +        /*
       +         *  take a larger increment to avoid mallocing too often
       +         */
       +        size = s->end-s->base;
       +        if(size/2 < incr)
       +                size += incr;
       +        else
       +                size += size/2;
       +
       +        cp = realloc(s->base, size);
       +        if (cp == 0)
       +                sysfatal("s_grow: %r");
       +        s->ptr = (s->ptr - s->base) + cp;
       +        s->end = cp + size;
       +        s->base = cp;
       +
       +        return s;
       +}
       +
 (DIR) diff --git a/src/libString/s_memappend.c b/src/libString/s_memappend.c
       t@@ -0,0 +1,20 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +/* append a char array ( of up to n characters) to a String */
       +String *
       +s_memappend(String *to, char *from, int n)
       +{
       +        char *e;
       +
       +        if (to == 0)
       +                to = s_new();
       +        if (from == 0)
       +                return to;
       +        for(e = from + n; from < e; from++)
       +                s_putc(to, *from);
       +        s_terminate(to);
       +        return to;
       +}
       +
 (DIR) diff --git a/src/libString/s_nappend.c b/src/libString/s_nappend.c
       t@@ -0,0 +1,18 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +/* append a char array ( of up to n characters) to a String */
       +String *
       +s_nappend(String *to, char *from, int n)
       +{
       +        if (to == 0)
       +                to = s_new();
       +        if (from == 0)
       +                return to;
       +        for(; n && *from; from++, n--)
       +                s_putc(to, *from);
       +        s_terminate(to);
       +        return to;
       +}
       +
 (DIR) diff --git a/src/libString/s_parse.c b/src/libString/s_parse.c
       t@@ -0,0 +1,40 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +#define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
       +
       +/* Get the next field from a String.  The field is delimited by white space,
       + * single or double quotes.
       + */
       +String *
       +s_parse(String *from, String *to)
       +{
       +        if (*from->ptr == '\0')
       +                return 0;
       +        if (to == 0)
       +                to = s_new();
       +        if (*from->ptr == '\'') {
       +                from->ptr++;
       +                for (;*from->ptr != '\'' && *from->ptr != '\0'; from->ptr++)
       +                        s_putc(to, *from->ptr);
       +                if (*from->ptr == '\'')        
       +                        from->ptr++;
       +        } else if (*from->ptr == '"') {
       +                from->ptr++;
       +                for (;*from->ptr != '"' && *from->ptr != '\0'; from->ptr++)
       +                        s_putc(to, *from->ptr);
       +                if (*from->ptr == '"')        
       +                        from->ptr++;
       +        } else {
       +                for (;!isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++)
       +                        s_putc(to, *from->ptr);
       +        }
       +        s_terminate(to);
       +
       +        /* crunch trailing white */
       +        while(isspace(*from->ptr))
       +                from->ptr++;
       +
       +        return to;
       +}
 (DIR) diff --git a/src/libString/s_putc.c b/src/libString/s_putc.c
       t@@ -0,0 +1,13 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +void
       +s_putc(String *s, int c)
       +{
       +        if(s->ref > 1)
       +                sysfatal("can't s_putc a shared string");
       +        if (s->ptr >= s->end)
       +                s_grow(s, 2);
       +        *(s->ptr)++ = c;
       +}
 (DIR) diff --git a/src/libString/s_rdinstack.c b/src/libString/s_rdinstack.c
       t@@ -0,0 +1,141 @@
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "libString.h"
       +
       +struct Sinstack{
       +        int        depth;
       +        Biobuf        *fp[32];        /* hard limit to avoid infinite recursion */
       +};
       +
       +/* initialize */
       +extern Sinstack *
       +s_allocinstack(char *file)
       +{
       +        Sinstack *sp;
       +        Biobuf *fp;
       +
       +        fp = Bopen(file, OREAD);
       +        if(fp == nil)
       +                return nil;
       +
       +        sp = malloc(sizeof *sp);
       +        sp->depth = 0;
       +        sp->fp[0] = fp;
       +        return sp;
       +}
       +
       +extern void
       +s_freeinstack(Sinstack *sp)
       +{
       +        while(sp->depth >= 0)
       +                Bterm(sp->fp[sp->depth--]);
       +        free(sp);
       +}
       +
       +/*  Append an input line to a String.
       + *
       + *  Empty lines and leading whitespace are removed.
       + */
       +static char *
       +rdline(Biobuf *fp, String *to)
       +{
       +        int c;
       +        int len = 0;
       +
       +        c = Bgetc(fp);
       +
       +        /* eat leading white */
       +        while(c==' ' || c=='\t' || c=='\n' || c=='\r')
       +                c = Bgetc(fp);
       +
       +        if(c < 0)
       +                return 0;
       +
       +        for(;;){
       +                switch(c) {
       +                case -1:
       +                        goto out;
       +                case '\\':
       +                        c = Bgetc(fp);
       +                        if (c != '\n') {
       +                                s_putc(to, '\\');
       +                                s_putc(to, c);
       +                                len += 2;
       +                        }
       +                        break;
       +                case '\r':
       +                        break;
       +                case '\n':
       +                        if(len != 0)
       +                                goto out;
       +                        break;
       +                default:
       +                        s_putc(to, c);
       +                        len++;
       +                        break;
       +                }
       +                c = Bgetc(fp);
       +        }
       +out:
       +        s_terminate(to);
       +        return to->ptr - len;
       +}
       +
       +/* Append an input line to a String.
       + *
       + * Returns a pointer to the character string (or 0).
       + * Leading whitespace and newlines are removed.
       + * Lines starting with #include cause us to descend into the new file.
       + * Empty lines and other lines starting with '#' are ignored.
       + */ 
       +extern char *
       +s_rdinstack(Sinstack *sp, String *to)
       +{
       +        char *p;
       +        Biobuf *fp, *nfp;
       +
       +        s_terminate(to);
       +        fp = sp->fp[sp->depth];
       +
       +        for(;;){
       +                p = rdline(fp, to);
       +                if(p == nil){
       +                        if(sp->depth == 0)
       +                                break;
       +                        Bterm(fp);
       +                        sp->depth--;
       +                        return s_rdinstack(sp, to);
       +                }
       +
       +                if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
       +                        to->ptr = p;
       +                        p += 8;
       +
       +                        /* sanity (and looping) */
       +                        if(sp->depth >= nelem(sp->fp))
       +                                sysfatal("s_recgetline: includes too deep");
       +
       +                        /* skip white */
       +                        while(*p == ' ' || *p == '\t')
       +                                p++;
       +
       +                        nfp = Bopen(p, OREAD);
       +                        if(nfp == nil)
       +                                continue;
       +                        sp->depth++;
       +                        sp->fp[sp->depth] = nfp;
       +                        return s_rdinstack(sp, to);
       +                }
       +
       +                /* got milk? */
       +                if(*p != '#')
       +                        break;
       +
       +                /* take care of comments */
       +                to->ptr = p;
       +                s_terminate(to);
       +        }
       +        return p;
       +}
 (DIR) diff --git a/src/libString/s_read.c b/src/libString/s_read.c
       t@@ -0,0 +1,38 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "libString.h"
       +
       +enum
       +{
       +        Minread=        256,
       +};
       +
       +/* Append up to 'len' input bytes to the string 'to'.
       + *
       + * Returns the number of characters read.
       + */ 
       +extern int
       +s_read(Biobuf *fp, String *to, int len)
       +{
       +        int rv;
       +        int n;
       +
       +        if(to->ref > 1)
       +                sysfatal("can't s_read a shared string");
       +        for(rv = 0; rv < len; rv += n){
       +                n = to->end - to->ptr;
       +                if(n < Minread){
       +                        s_grow(to, Minread);
       +                        n = to->end - to->ptr;
       +                }
       +                if(n > len - rv)
       +                        n = len - rv;
       +                n = Bread(fp, to->ptr, n);
       +                if(n <= 0)
       +                        break;
       +                to->ptr += n;
       +        }
       +        s_terminate(to);
       +        return rv;
       +}
 (DIR) diff --git a/src/libString/s_read_line.c b/src/libString/s_read_line.c
       t@@ -0,0 +1,31 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "libString.h"
       +
       +/* Append an input line to a String.
       + *
       + * Returns a pointer to the character string (or 0).
       + * Trailing newline is left on.
       + */ 
       +extern char *
       +s_read_line(Biobuf *fp, String *to)
       +{
       +        char *cp;
       +        int llen;
       +
       +        if(to->ref > 1)
       +                sysfatal("can't s_read_line a shared string");
       +        s_terminate(to);
       +        cp = Brdline(fp, '\n');
       +        if(cp == 0)
       +                return 0;
       +        llen = Blinelen(fp);
       +        if(to->end - to->ptr < llen)
       +                s_grow(to, llen);
       +        memmove(to->ptr, cp, llen);
       +        cp = to->ptr;
       +        to->ptr += llen;
       +        s_terminate(to);
       +        return cp;
       +}
 (DIR) diff --git a/src/libString/s_reset.c b/src/libString/s_reset.c
       t@@ -0,0 +1,23 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +String*
       +s_reset(String *s)
       +{
       +        if(s != nil){
       +                s = s_unique(s);
       +                s->ptr = s->base;
       +                *s->ptr = '\0';
       +        } else
       +                s = s_new();
       +        return s;
       +}
       +
       +String*
       +s_restart(String *s)
       +{
       +        s = s_unique(s);
       +        s->ptr = s->base;
       +        return s;
       +}
 (DIR) diff --git a/src/libString/s_terminate.c b/src/libString/s_terminate.c
       t@@ -0,0 +1,13 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +void
       +s_terminate(String *s)
       +{
       +        if(s->ref > 1)
       +                sysfatal("can't s_terminate a shared string");
       +        if (s->ptr >= s->end)
       +                s_grow(s, 1);
       +        *s->ptr = 0;
       +}
 (DIR) diff --git a/src/libString/s_tolower.c b/src/libString/s_tolower.c
       t@@ -0,0 +1,15 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ctype.h>
       +#include "libString.h"
       +
       +
       +/* convert String to lower case */
       +void
       +s_tolower(String *sp)
       +{
       +        char *cp;
       +
       +        for(cp=sp->ptr; *cp; cp++)
       +                *cp = tolower(*cp);
       +}
 (DIR) diff --git a/src/libString/s_unique.c b/src/libString/s_unique.c
       t@@ -0,0 +1,16 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "libString.h"
       +
       +String*
       +s_unique(String *s)
       +{
       +        String *p;
       +
       +        if(s->ref > 1){
       +                p = s;
       +                s = s_clone(p);
       +                s_free(p);
       +        }
       +        return s;
       +}