commit 7f11104a5737adf261d10bc1a7b85e740f2eb491 from: rsc date: Thu Dec 11 18:15:57 2003 UTC Add libString. commit - 57ccfb9e8f51138c33ad5f58e14c0e54246cf5c4 commit + 7f11104a5737adf261d10bc1a7b85e740f2eb491 blob - /dev/null blob + 019ad732285e4fc024dd17b2b9e38a816fc92294 (mode 644) --- /dev/null +++ include/html.h @@ -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<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 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 blob - /dev/null blob + d84870664e9f2ffcd6a93d5a6c514659645d39df (mode 644) --- /dev/null +++ include/libString.h @@ -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 blob - /dev/null blob + 49803b45115bbc4748cf779d51bdd867ef1c977c (mode 644) --- /dev/null +++ src/libString/mkfile @@ -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 blob - /dev/null blob + 34f8916422c1419579c2721fdabf2618b90bde74 (mode 644) --- /dev/null +++ src/libString/s_alloc.c @@ -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; +} blob - /dev/null blob + 1b02d20eb80e8c83b2d56bb43e0100da1789410d (mode 644) --- /dev/null +++ src/libString/s_append.c @@ -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; +} blob - /dev/null blob + 3cf571b16785568cb67700f625f6933ec30b394c (mode 644) --- /dev/null +++ src/libString/s_array.c @@ -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; +} blob - /dev/null blob + 5a23b3c2036bbd132e9b3e51c44131b03b096a14 (mode 644) --- /dev/null +++ src/libString/s_copy.c @@ -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; +} blob - /dev/null blob + e46dc125fb0d1f8a67341dc614a169aa8f32efa2 (mode 644) --- /dev/null +++ src/libString/s_getline.c @@ -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; +} blob - /dev/null blob + 5cf2a1414ceb01f50e3e2e2990ce7df75d15bc26 (mode 644) --- /dev/null +++ src/libString/s_grow.c @@ -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; +} + blob - /dev/null blob + 27b69850ea0f1ba3dd17a159884e75933dcfb112 (mode 644) --- /dev/null +++ src/libString/s_memappend.c @@ -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; +} + blob - /dev/null blob + fb41f9328c3576c47a6330c2b747ec205e0fee18 (mode 644) --- /dev/null +++ src/libString/s_nappend.c @@ -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; +} + blob - /dev/null blob + 376a41e29fa7e9c91d43113b278e7e83a4986b98 (mode 644) --- /dev/null +++ src/libString/s_parse.c @@ -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; +} blob - /dev/null blob + 29a385d767be5b092780cb80a7b99c6f3f691d38 (mode 644) --- /dev/null +++ src/libString/s_putc.c @@ -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; +} blob - /dev/null blob + de12d2193d2925d05d90db1e61a6d7dbdbb25728 (mode 644) --- /dev/null +++ src/libString/s_rdinstack.c @@ -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; +} blob - /dev/null blob + 59581eaf613cd55abdde8d2ce7df1b3e0c16a40c (mode 644) --- /dev/null +++ src/libString/s_read.c @@ -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; +} blob - /dev/null blob + b1de5ac458fd24092c55a3751b5b62c5749e2ac3 (mode 644) --- /dev/null +++ src/libString/s_read_line.c @@ -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; +} blob - /dev/null blob + cd2a7421b548229c6ee48ef971416fc0e2362e93 (mode 644) --- /dev/null +++ src/libString/s_reset.c @@ -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; +} blob - /dev/null blob + dc893ab23963f143d0d65e996507a6f7713cd551 (mode 644) --- /dev/null +++ src/libString/s_terminate.c @@ -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; +} blob - /dev/null blob + 737fff1f2e9a9201a47f27cf98329f83cc4cb6ed (mode 644) --- /dev/null +++ src/libString/s_tolower.c @@ -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); +} blob - /dev/null blob + 134411c92ecdcebecc3c2c82649c23baa232fd2f (mode 644) --- /dev/null +++ src/libString/s_unique.c @@ -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; +}