Add libString.

This commit is contained in:
rsc 2003-12-11 18:15:57 +00:00
parent 57ccfb9e8f
commit 7f11104a57
20 changed files with 1315 additions and 0 deletions

629
include/html.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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;
}

View 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
View 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
View 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;
}