mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-24 11:41:58 +00:00
Add libString.
This commit is contained in:
parent
57ccfb9e8f
commit
7f11104a57
20 changed files with 1315 additions and 0 deletions
629
include/html.h
Normal file
629
include/html.h
Normal file
|
@ -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
|
46
include/libString.h
Normal file
46
include/libString.h
Normal file
|
@ -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
|
27
src/libString/mkfile
Normal file
27
src/libString/mkfile
Normal file
|
@ -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
|
86
src/libString/s_alloc.c
Normal file
86
src/libString/s_alloc.c
Normal file
|
@ -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;
|
||||
}
|
17
src/libString/s_append.c
Normal file
17
src/libString/s_append.c
Normal file
|
@ -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;
|
||||
}
|
17
src/libString/s_array.c
Normal file
17
src/libString/s_array.c
Normal file
|
@ -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;
|
||||
}
|
19
src/libString/s_copy.c
Normal file
19
src/libString/s_copy.c
Normal file
|
@ -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;
|
||||
}
|
72
src/libString/s_getline.c
Normal file
72
src/libString/s_getline.c
Normal file
|
@ -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;
|
||||
}
|
34
src/libString/s_grow.c
Normal file
34
src/libString/s_grow.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
20
src/libString/s_memappend.c
Normal file
20
src/libString/s_memappend.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
18
src/libString/s_nappend.c
Normal file
18
src/libString/s_nappend.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
40
src/libString/s_parse.c
Normal file
40
src/libString/s_parse.c
Normal file
|
@ -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;
|
||||
}
|
13
src/libString/s_putc.c
Normal file
13
src/libString/s_putc.c
Normal file
|
@ -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;
|
||||
}
|
141
src/libString/s_rdinstack.c
Normal file
141
src/libString/s_rdinstack.c
Normal file
|
@ -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;
|
||||
}
|
38
src/libString/s_read.c
Normal file
38
src/libString/s_read.c
Normal file
|
@ -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;
|
||||
}
|
31
src/libString/s_read_line.c
Normal file
31
src/libString/s_read_line.c
Normal file
|
@ -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;
|
||||
}
|
23
src/libString/s_reset.c
Normal file
23
src/libString/s_reset.c
Normal file
|
@ -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;
|
||||
}
|
13
src/libString/s_terminate.c
Normal file
13
src/libString/s_terminate.c
Normal file
|
@ -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;
|
||||
}
|
15
src/libString/s_tolower.c
Normal file
15
src/libString/s_tolower.c
Normal file
|
@ -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);
|
||||
}
|
16
src/libString/s_unique.c
Normal file
16
src/libString/s_unique.c
Normal file
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue