libc: initial import from Harvey
Note that libc is what distinguish "native" software from "non-native" in Jehanne: further C libraries can be ported to Jehanne, but this libc will remain the main building block of the system. Also note that a few files have not been ported from Harvey: - 9sys/pushtls.c - port/rijndael.c - port/rijndael.tbl - port/sha2.c Pushtls.c depends on libmp and libsec so libc is not the appropriate place for it. The other three will be moved to libsec.
This commit is contained in:
parent
e4ebd7eace
commit
3925b61fa6
38
sys/include/ctype.h
Normal file
38
sys/include/ctype.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma src "/sys/src/libc/port"
|
||||
#pragma lib "libc.a"
|
||||
|
||||
#define _U 01
|
||||
#define _L 02
|
||||
#define _N 04
|
||||
#define _S 010
|
||||
#define _P 020
|
||||
#define _C 040
|
||||
#define _B 0100
|
||||
#define _X 0200
|
||||
|
||||
extern unsigned char _ctype[];
|
||||
|
||||
#define isalpha(c) (_ctype[(unsigned char)(c)]&(_U|_L))
|
||||
#define isupper(c) (_ctype[(unsigned char)(c)]&_U)
|
||||
#define islower(c) (_ctype[(unsigned char)(c)]&_L)
|
||||
#define isdigit(c) (_ctype[(unsigned char)(c)]&_N)
|
||||
#define isxdigit(c) (_ctype[(unsigned char)(c)]&_X)
|
||||
#define isspace(c) (_ctype[(unsigned char)(c)]&_S)
|
||||
#define ispunct(c) (_ctype[(unsigned char)(c)]&_P)
|
||||
#define isalnum(c) (_ctype[(unsigned char)(c)]&(_U|_L|_N))
|
||||
#define isprint(c) (_ctype[(unsigned char)(c)]&(_P|_U|_L|_N|_B))
|
||||
#define isgraph(c) (_ctype[(unsigned char)(c)]&(_P|_U|_L|_N))
|
||||
#define iscntrl(c) (_ctype[(unsigned char)(c)]&_C)
|
||||
#define isascii(c) ((unsigned char)(c)<=0177)
|
||||
#define _toupper(c) ((c)-'a'+'A')
|
||||
#define _tolower(c) ((c)-'A'+'a')
|
||||
#define toascii(c) ((c)&0177)
|
149
sys/include/fcall.h
Normal file
149
sys/include/fcall.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma src "/sys/src/libc/9sys"
|
||||
#pragma lib "libc.a"
|
||||
|
||||
#define VERSION9P "9P2000"
|
||||
|
||||
#define MAXWELEM 16
|
||||
|
||||
typedef
|
||||
struct Fcall
|
||||
{
|
||||
uint8_t type;
|
||||
uint32_t fid;
|
||||
uint16_t tag;
|
||||
union {
|
||||
struct {
|
||||
uint32_t msize; /* Tversion, Rversion */
|
||||
char *version; /* Tversion, Rversion */
|
||||
};
|
||||
struct {
|
||||
uint16_t oldtag; /* Tflush */
|
||||
};
|
||||
struct {
|
||||
char *ename; /* Rerror */
|
||||
};
|
||||
struct {
|
||||
Qid qid; /* Rattach, Ropen, Rcreate */
|
||||
uint32_t iounit; /* Ropen, Rcreate */
|
||||
};
|
||||
struct {
|
||||
Qid aqid; /* Rauth */
|
||||
};
|
||||
struct {
|
||||
uint32_t afid; /* Tauth, Tattach */
|
||||
char *uname; /* Tauth, Tattach */
|
||||
char *aname; /* Tauth, Tattach */
|
||||
};
|
||||
struct {
|
||||
uint32_t perm; /* Tcreate */
|
||||
char *name; /* Tcreate */
|
||||
uint8_t mode; /* Tcreate, Topen */
|
||||
};
|
||||
struct {
|
||||
uint32_t newfid; /* Twalk */
|
||||
uint16_t nwname; /* Twalk */
|
||||
char *wname[MAXWELEM]; /* Twalk */
|
||||
};
|
||||
struct {
|
||||
uint16_t nwqid; /* Rwalk */
|
||||
Qid wqid[MAXWELEM]; /* Rwalk */
|
||||
};
|
||||
struct {
|
||||
int64_t offset; /* Tread, Twrite */
|
||||
uint32_t count; /* Tread, Twrite, Rread */
|
||||
char *data; /* Twrite, Rread */
|
||||
};
|
||||
struct {
|
||||
uint16_t nstat; /* Twstat, Rstat */
|
||||
uint8_t *stat; /* Twstat, Rstat */
|
||||
};
|
||||
};
|
||||
} Fcall;
|
||||
|
||||
|
||||
#define GBIT8(p) ((p)[0])
|
||||
#define GBIT16(p) ((p)[0]|((p)[1]<<8))
|
||||
#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
|
||||
#define GBIT64(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
|
||||
((int64_t)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
|
||||
|
||||
#define PBIT8(p,v) (p)[0]=(v)
|
||||
#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
|
||||
#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
|
||||
#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
|
||||
(p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
|
||||
|
||||
#define BIT8SZ 1
|
||||
#define BIT16SZ 2
|
||||
#define BIT32SZ 4
|
||||
#define BIT64SZ 8
|
||||
#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ)
|
||||
|
||||
/* STATFIXLEN includes leading 16-bit count */
|
||||
/* The count, however, excludes itself; total size is BIT16SZ+count */
|
||||
#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */
|
||||
|
||||
#define NOTAG (uint16_t)~0U /* Dummy tag */
|
||||
#define NOFID (uint32_t)~0U /* Dummy fid */
|
||||
#define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */
|
||||
|
||||
enum
|
||||
{
|
||||
Tversion = 100,
|
||||
Rversion,
|
||||
Tauth = 102,
|
||||
Rauth,
|
||||
Tattach = 104,
|
||||
Rattach,
|
||||
Terror = 106, /* illegal */
|
||||
Rerror,
|
||||
Tflush = 108,
|
||||
Rflush,
|
||||
Twalk = 110,
|
||||
Rwalk,
|
||||
Topen = 112,
|
||||
Ropen,
|
||||
Tcreate = 114,
|
||||
Rcreate,
|
||||
Tread = 116,
|
||||
Rread,
|
||||
Twrite = 118,
|
||||
Rwrite,
|
||||
Tclunk = 120,
|
||||
Rclunk,
|
||||
Tremove = 122,
|
||||
Rremove,
|
||||
Tstat = 124,
|
||||
Rstat,
|
||||
Twstat = 126,
|
||||
Rwstat,
|
||||
Tmax,
|
||||
};
|
||||
|
||||
uint convM2S(uint8_t*, uint, Fcall*);
|
||||
uint convS2M(Fcall*, uint8_t*, uint);
|
||||
uint sizeS2M(Fcall*);
|
||||
|
||||
int statcheck(uint8_t *abuf, uint nbuf);
|
||||
uint convM2D(uint8_t*, uint, Dir*, char*);
|
||||
uint convD2M(Dir*, uint8_t*, uint);
|
||||
uint sizeD2M(Dir*);
|
||||
|
||||
int fcallfmt(Fmt*);
|
||||
int dirfmt(Fmt*);
|
||||
int dirmodefmt(Fmt*);
|
||||
|
||||
int read9pmsg(int, void*, uint);
|
||||
|
||||
#pragma varargck type "F" Fcall*
|
||||
#pragma varargck type "M" ulong
|
||||
#pragma varargck type "D" Dir*
|
763
sys/include/libc.h
Normal file
763
sys/include/libc.h
Normal file
@ -0,0 +1,763 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma lib "libc.a"
|
||||
#pragma src "/sys/src/libc"
|
||||
|
||||
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#define offsetof(s, m) (uintptr_t)(&(((s*)0)->m))
|
||||
#define assert(x) if(x){}else _assert(#x)
|
||||
|
||||
extern void (*_abort)(void);
|
||||
#define abort() if(_abort){_abort();}else{while(*(int*)0);}
|
||||
|
||||
/*
|
||||
* mem routines
|
||||
*/
|
||||
extern void* memccpy(void*, const void*, int, uint32_t);
|
||||
extern void* memset(void*, int, uint32_t);
|
||||
extern int memcmp(const void*, const void*, uint32_t);
|
||||
extern void* memcpy(void*, const void*, size_t);
|
||||
extern void* memmove(void*, const void*, size_t);
|
||||
extern void* memchr(const void*, int, uint32_t);
|
||||
|
||||
/*
|
||||
* string routines
|
||||
*/
|
||||
extern char* strcat(char*, const char*);
|
||||
extern char* strchr(const char*, int);
|
||||
extern int strcmp(const char*, const char*);
|
||||
extern char* strcpy(char*, const char*);
|
||||
extern char* strecpy(char*, char *, const char*);
|
||||
extern char* strdup(const char*);
|
||||
extern char* strncat(char*, const char*, int32_t);
|
||||
extern char* strncpy(char*, const char*, uint32_t);
|
||||
extern int strncmp(const char*, const char*, int32_t);
|
||||
extern char* strpbrk(const char*, const char*);
|
||||
extern char* strrchr(const char*, int);
|
||||
extern char* strtok(char*, char*);
|
||||
extern int32_t strlen(const char*);
|
||||
extern int32_t strspn(const char*, const char*);
|
||||
extern int32_t strcspn(const char*, const char*);
|
||||
extern char* strstr(const char*, const char*);
|
||||
extern int cistrncmp(const char*, const char*, int);
|
||||
extern int cistrcmp(const char*, const char*);
|
||||
extern char* cistrstr(const char*, const char*);
|
||||
extern int tokenize(char*, char**, int);
|
||||
|
||||
enum
|
||||
{
|
||||
UTFmax = 4, /* maximum bytes per rune */
|
||||
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
|
||||
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
|
||||
Runeerror = 0xFFFD, /* decoding error in UTF */
|
||||
Runemax = 0x10FFFF, /* 21-bit rune */
|
||||
Runemask = 0x1FFFFF, /* bits used by runes (see grep) */
|
||||
};
|
||||
|
||||
/*
|
||||
* rune routines
|
||||
*/
|
||||
extern int runetochar(char*, const Rune*);
|
||||
extern int chartorune(Rune*, const char*);
|
||||
extern int runelen(Rune);
|
||||
extern int runenlen(const Rune*, int);
|
||||
extern int fullrune(const char*, int);
|
||||
extern int utflen(const char*);
|
||||
extern int utfnlen(const char*, int32_t);
|
||||
extern char* utfrune(const char*, Rune);
|
||||
extern char* utfrrune(const char*, Rune);
|
||||
extern char* utfutf(const char*, const char*);
|
||||
extern char* utfecpy(char*, char *, const char*);
|
||||
|
||||
extern Rune* runestrcat(Rune*, const Rune*);
|
||||
extern Rune* runestrchr(const Rune*, Rune);
|
||||
extern int runestrcmp(const Rune*, const Rune*);
|
||||
extern Rune* runestrcpy(Rune*, const Rune*);
|
||||
extern Rune* runestrncpy(Rune*, const Rune*, int32_t);
|
||||
extern Rune* runestrecpy(Rune*, Rune*, const Rune*);
|
||||
extern Rune* runestrdup(const Rune*);
|
||||
extern Rune* runestrncat(Rune*, const Rune*, int32_t);
|
||||
extern int runestrncmp(const Rune*, const Rune*, int32_t);
|
||||
extern Rune* runestrrchr(const Rune*, Rune);
|
||||
extern int32_t runestrlen(const Rune*);
|
||||
extern Rune* runestrstr(const Rune*, const Rune*);
|
||||
|
||||
extern Rune tolowerrune(Rune);
|
||||
extern Rune totitlerune(Rune);
|
||||
extern Rune toupperrune(Rune);
|
||||
extern Rune tobaserune(Rune);
|
||||
extern int isalpharune(Rune);
|
||||
extern int isbaserune(Rune);
|
||||
extern int isdigitrune(Rune);
|
||||
extern int islowerrune(Rune);
|
||||
extern int isspacerune(Rune);
|
||||
extern int istitlerune(Rune);
|
||||
extern int isupperrune(Rune);
|
||||
|
||||
/*
|
||||
* malloc
|
||||
*/
|
||||
extern void* malloc(size_t);
|
||||
extern void* mallocz(uint32_t, int);
|
||||
extern void free(void*);
|
||||
extern uint32_t msize(void*);
|
||||
extern void* mallocalign(uint32_t, uint32_t, int32_t, uint32_t);
|
||||
extern void* calloc(uint32_t, size_t);
|
||||
extern void* realloc(void*, size_t);
|
||||
void setmalloctag(void*, uintptr_t);
|
||||
void setrealloctag(void*, uintptr_t);
|
||||
uintptr_t getmalloctag(void*);
|
||||
uintptr_t getrealloctag(void*);
|
||||
void* malloctopoolblock(void*);
|
||||
|
||||
/*
|
||||
* print routines
|
||||
*/
|
||||
typedef struct Fmt Fmt;
|
||||
struct Fmt{
|
||||
uint8_t runes; /* output buffer is runes or chars? */
|
||||
void *start; /* of buffer */
|
||||
void *to; /* current place in the buffer */
|
||||
void *stop; /* end of the buffer; overwritten if flush fails */
|
||||
int (*flush)(Fmt *); /* called when to == stop */
|
||||
void *farg; /* to make flush a closure */
|
||||
int nfmt; /* num chars formatted so far */
|
||||
va_list args; /* args passed to dofmt */
|
||||
int r; /* % format Rune */
|
||||
int width;
|
||||
int prec;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
enum{
|
||||
FmtWidth = 1,
|
||||
FmtLeft = FmtWidth << 1,
|
||||
FmtPrec = FmtLeft << 1,
|
||||
FmtSharp = FmtPrec << 1,
|
||||
FmtSpace = FmtSharp << 1,
|
||||
FmtSign = FmtSpace << 1,
|
||||
FmtZero = FmtSign << 1,
|
||||
FmtUnsigned = FmtZero << 1,
|
||||
FmtShort = FmtUnsigned << 1,
|
||||
FmtLong = FmtShort << 1,
|
||||
FmtVLong = FmtLong << 1,
|
||||
FmtComma = FmtVLong << 1,
|
||||
FmtByte = FmtComma << 1,
|
||||
|
||||
FmtFlag = FmtByte << 1
|
||||
};
|
||||
|
||||
extern int print(const char*, ...);
|
||||
extern char* seprint(char*, char*, const char*, ...);
|
||||
extern char* vseprint(char*, char*, const char*, va_list);
|
||||
extern int snprint(char*, int, const char*, ...);
|
||||
extern int vsnprint(char*, int, const char*, va_list);
|
||||
extern char* smprint(const char*, ...);
|
||||
extern char* vsmprint(const char*, va_list);
|
||||
extern int sprint(char*, const char*, ...);
|
||||
extern int fprint(int, const char*, ...);
|
||||
extern int vfprint(int, const char*, va_list);
|
||||
|
||||
extern int runesprint(Rune*, const char*, ...);
|
||||
extern int runesnprint(Rune*, int, const char*, ...);
|
||||
extern int runevsnprint(Rune*, int, const char*, va_list);
|
||||
extern Rune* runeseprint(Rune*, Rune*, const char*, ...);
|
||||
extern Rune* runevseprint(Rune*, Rune*, const char*, va_list);
|
||||
extern Rune* runesmprint(const char*, ...);
|
||||
extern Rune* runevsmprint(const char*, va_list);
|
||||
|
||||
extern int fmtfdinit(Fmt*, int, char*, int);
|
||||
extern int fmtfdflush(Fmt*);
|
||||
extern int fmtstrinit(Fmt*);
|
||||
extern char* fmtstrflush(Fmt*);
|
||||
extern int runefmtstrinit(Fmt*);
|
||||
extern Rune* runefmtstrflush(Fmt*);
|
||||
|
||||
#pragma varargck argpos fmtprint 2
|
||||
#pragma varargck argpos fprint 2
|
||||
#pragma varargck argpos print 1
|
||||
#pragma varargck argpos runeseprint 3
|
||||
#pragma varargck argpos runesmprint 1
|
||||
#pragma varargck argpos runesnprint 3
|
||||
#pragma varargck argpos runesprint 2
|
||||
#pragma varargck argpos seprint 3
|
||||
#pragma varargck argpos smprint 1
|
||||
#pragma varargck argpos snprint 3
|
||||
#pragma varargck argpos sprint 2
|
||||
|
||||
#pragma varargck type "lld" vlong
|
||||
#pragma varargck type "llo" vlong
|
||||
#pragma varargck type "llx" vlong
|
||||
#pragma varargck type "llb" vlong
|
||||
#pragma varargck type "lld" uvlong
|
||||
#pragma varargck type "llo" uvlong
|
||||
#pragma varargck type "llx" uvlong
|
||||
#pragma varargck type "llb" uvlong
|
||||
#pragma varargck type "ld" long
|
||||
#pragma varargck type "lo" long
|
||||
#pragma varargck type "lx" long
|
||||
#pragma varargck type "lb" long
|
||||
#pragma varargck type "ld" ulong
|
||||
#pragma varargck type "lo" ulong
|
||||
#pragma varargck type "lx" ulong
|
||||
#pragma varargck type "lb" ulong
|
||||
#pragma varargck type "d" int
|
||||
#pragma varargck type "o" int
|
||||
#pragma varargck type "x" int
|
||||
#pragma varargck type "c" int
|
||||
#pragma varargck type "C" int
|
||||
#pragma varargck type "b" int
|
||||
#pragma varargck type "d" uint
|
||||
#pragma varargck type "x" uint
|
||||
#pragma varargck type "c" uint
|
||||
#pragma varargck type "C" uint
|
||||
#pragma varargck type "b" uint
|
||||
#pragma varargck type "f" double
|
||||
#pragma varargck type "e" double
|
||||
#pragma varargck type "g" double
|
||||
#pragma varargck type "s" char*
|
||||
#pragma varargck type "q" char*
|
||||
#pragma varargck type "S" Rune*
|
||||
#pragma varargck type "Q" Rune*
|
||||
#pragma varargck type "r" void
|
||||
#pragma varargck type "%" void
|
||||
#pragma varargck type "n" int*
|
||||
#pragma varargck type "p" uintptr
|
||||
#pragma varargck type "p" void*
|
||||
#pragma varargck flag ','
|
||||
#pragma varargck flag ' '
|
||||
#pragma varargck flag 'h'
|
||||
#pragma varargck type "<" void*
|
||||
#pragma varargck type "[" void*
|
||||
#pragma varargck type "H" void*
|
||||
#pragma varargck type "lH" void*
|
||||
|
||||
extern int fmtinstall(int, int (*)(Fmt*));
|
||||
extern int dofmt(Fmt*, const char*);
|
||||
extern int dorfmt(Fmt*, const Rune*);
|
||||
extern int fmtprint(Fmt*, const char*, ...);
|
||||
extern int fmtvprint(Fmt*, const char*, va_list);
|
||||
extern int fmtrune(Fmt*, int);
|
||||
extern int fmtstrcpy(Fmt*, const char*);
|
||||
extern int fmtrunestrcpy(Fmt*, const Rune*);
|
||||
/*
|
||||
* error string for %r
|
||||
* supplied on per os basis, not part of fmt library
|
||||
*/
|
||||
extern int errfmt(Fmt *f);
|
||||
|
||||
/*
|
||||
* quoted strings
|
||||
*/
|
||||
extern char *unquotestrdup(const char*);
|
||||
extern Rune *unquoterunestrdup(const Rune*);
|
||||
extern char *quotestrdup(const char*);
|
||||
extern Rune *quoterunestrdup(const Rune*);
|
||||
extern int quotestrfmt(Fmt*);
|
||||
extern int quoterunestrfmt(Fmt*);
|
||||
extern void quotefmtinstall(void);
|
||||
extern int (*doquote)(int);
|
||||
extern int needsrcquote(int);
|
||||
|
||||
/*
|
||||
* random number
|
||||
*/
|
||||
extern void srand(int32_t);
|
||||
extern int rand(void);
|
||||
extern int nrand(int);
|
||||
extern int32_t lrand(void);
|
||||
extern int32_t lnrand(int32_t);
|
||||
extern double frand(void);
|
||||
extern uint32_t truerand(void); /* uses /dev/random */
|
||||
extern uint32_t ntruerand(uint32_t); /* uses /dev/random */
|
||||
|
||||
/*
|
||||
* math
|
||||
*/
|
||||
extern uint32_t getfcr(void);
|
||||
extern void setfsr(uint32_t);
|
||||
extern uint32_t getfsr(void);
|
||||
extern void setfcr(uint32_t);
|
||||
extern double NaN(void);
|
||||
extern double Inf(int);
|
||||
extern int isNaN(double);
|
||||
extern int isInf(double, int);
|
||||
extern uint32_t umuldiv(uint32_t, uint32_t, uint32_t);
|
||||
extern int32_t muldiv(int32_t, int32_t, int32_t);
|
||||
|
||||
extern double pow(double, double);
|
||||
extern double atan2(double, double);
|
||||
extern double fabs(double);
|
||||
extern double atan(double);
|
||||
extern double log(double);
|
||||
extern double log10(double);
|
||||
extern double exp(double);
|
||||
extern double floor(double);
|
||||
extern double ceil(double);
|
||||
extern double hypot(double, double);
|
||||
extern double sin(double);
|
||||
extern double cos(double);
|
||||
extern double tan(double);
|
||||
extern double asin(double);
|
||||
extern double acos(double);
|
||||
extern double sinh(double);
|
||||
extern double cosh(double);
|
||||
extern double tanh(double);
|
||||
extern double sqrt(double);
|
||||
extern double fmod(double, double);
|
||||
|
||||
#define HUGE 3.4028234e38
|
||||
#define PIO2 1.570796326794896619231e0
|
||||
#define PI (PIO2+PIO2)
|
||||
|
||||
/*
|
||||
* Time-of-day
|
||||
*/
|
||||
|
||||
typedef
|
||||
struct Tm
|
||||
{
|
||||
int sec;
|
||||
int min;
|
||||
int hour;
|
||||
int mday;
|
||||
int mon;
|
||||
int year;
|
||||
int wday;
|
||||
int yday;
|
||||
char zone[4];
|
||||
int tzoff;
|
||||
} Tm;
|
||||
|
||||
extern Tm* gmtime(int32_t);
|
||||
extern Tm* localtime(int32_t);
|
||||
extern char* asctime(Tm*);
|
||||
extern char* ctime(int32_t);
|
||||
extern double cputime(void);
|
||||
extern int32_t times(int32_t*);
|
||||
extern int32_t tm2sec(Tm*);
|
||||
extern int64_t nsec(void);
|
||||
|
||||
extern void cycles(uint64_t*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */
|
||||
|
||||
/*
|
||||
* one-of-a-kind
|
||||
*/
|
||||
enum
|
||||
{
|
||||
PNPROC = 1,
|
||||
PNGROUP = 2,
|
||||
};
|
||||
|
||||
extern void _assert(const char*);
|
||||
extern int abs(int);
|
||||
extern int atexit(void(*)(void));
|
||||
extern void atexitdont(void(*)(void));
|
||||
extern int atnotify(int(*)(void*, char*), int);
|
||||
extern double atof(const char*);
|
||||
extern int atoi(const char*);
|
||||
extern int32_t atol(const char*);
|
||||
extern int64_t atoll(const char*);
|
||||
extern double charstod(int(*)(void*), void*);
|
||||
extern char* cleanname(char*);
|
||||
extern int decrypt(void*, void*, int);
|
||||
extern int encrypt(void*, void*, int);
|
||||
extern int dec64(uint8_t*, int, const char*, int);
|
||||
extern int enc64(char*, int, const uint8_t*, int);
|
||||
extern int dec32(uint8_t*, int, const char*, int);
|
||||
extern int enc32(char*, int, const uint8_t*, int);
|
||||
extern int dec16(uint8_t*, int, const char*, int);
|
||||
extern int enc16(char*, int, const uint8_t*, int);
|
||||
extern int encodefmt(Fmt*);
|
||||
extern void exits(const char*);
|
||||
extern double frexp(double, int*);
|
||||
extern uintptr getcallerpc(void);
|
||||
extern char* getenv(const char*);
|
||||
extern int getfields(char*, char**, int, int, const char*);
|
||||
extern int gettokens(char *, char **, int, const char *);
|
||||
extern char* getuser(void);
|
||||
extern char* getwd(char*, int);
|
||||
extern int iounit(int);
|
||||
extern int32_t labs(int32_t);
|
||||
extern double ldexp(double, int);
|
||||
extern void longjmp(jmp_buf, int);
|
||||
extern char* mktemp(char*);
|
||||
extern double modf(double, double*);
|
||||
extern void notejmp(void*, jmp_buf, int);
|
||||
extern void perror(const char*);
|
||||
extern int postnote(int, int, const char *);
|
||||
extern double pow10(int);
|
||||
extern int putenv(const char*, const char*);
|
||||
extern void qsort(void*, int32_t, int32_t,
|
||||
int (*)(const void*, const void*));
|
||||
extern int setjmp(jmp_buf);
|
||||
extern double strtod(const char*, const char**);
|
||||
extern int32_t strtol(const char*, char**, int);
|
||||
extern uint32_t strtoul(const char*, char**, int);
|
||||
extern int64_t strtoll(const char*, char**, int);
|
||||
extern uint64_t strtoull(const char*, char**, int);
|
||||
extern void sysfatal(const char*, ...);
|
||||
#pragma varargck argpos sysfatal 1
|
||||
extern void syslog(int, const char*, const char*, ...);
|
||||
#pragma varargck argpos syslog 3
|
||||
extern int32_t time(int32_t*);
|
||||
extern int tolower(int);
|
||||
extern int toupper(int);
|
||||
|
||||
/*
|
||||
* atomic
|
||||
*/
|
||||
int32_t ainc(int32_t*);
|
||||
int32_t adec(int32_t*);
|
||||
int cas32(uint32_t*, uint32_t, uint32_t);
|
||||
int casp(void**, void*, void*);
|
||||
int casl(uint32_t*, uint32_t, uint32_t);
|
||||
|
||||
/*
|
||||
* synchronization
|
||||
*/
|
||||
typedef
|
||||
struct Lock {
|
||||
int32_t key;
|
||||
int32_t sem;
|
||||
} Lock;
|
||||
|
||||
extern int _tas(int*);
|
||||
|
||||
extern void lock(Lock*);
|
||||
extern int lockt(Lock*, uint32_t);
|
||||
extern void unlock(Lock*);
|
||||
extern int canlock(Lock*);
|
||||
|
||||
typedef struct QLp QLp;
|
||||
struct QLp
|
||||
{
|
||||
int inuse;
|
||||
QLp *next;
|
||||
char state;
|
||||
};
|
||||
|
||||
typedef
|
||||
struct QLock
|
||||
{
|
||||
Lock lock;
|
||||
int locked;
|
||||
QLp *head;
|
||||
QLp *tail;
|
||||
} QLock;
|
||||
|
||||
extern void qlock(QLock*);
|
||||
extern int qlockt(QLock*, uint32_t);
|
||||
extern void qunlock(QLock*);
|
||||
extern int canqlock(QLock*);
|
||||
extern void _qlockinit(void* (*)(void*, void*)); /* called only by the thread library */
|
||||
|
||||
typedef
|
||||
struct RWLock
|
||||
{
|
||||
Lock lock;
|
||||
int _readers; /* number of readers */
|
||||
int writer; /* number of writers */
|
||||
QLp *head; /* list of waiting processes */
|
||||
QLp *tail;
|
||||
} RWLock;
|
||||
|
||||
extern void rlock(RWLock*);
|
||||
extern int rlockt(RWLock*, uint32_t);
|
||||
extern void runlock(RWLock*);
|
||||
extern int canrlock(RWLock*);
|
||||
extern void wlock(RWLock*);
|
||||
extern int wlockt(RWLock*, uint32_t);
|
||||
extern void wunlock(RWLock*);
|
||||
extern int canwlock(RWLock*);
|
||||
|
||||
typedef
|
||||
struct Rendez
|
||||
{
|
||||
QLock *l;
|
||||
QLp *head;
|
||||
QLp *tail;
|
||||
} Rendez;
|
||||
|
||||
extern void rsleep(Rendez*); /* unlocks r->l, sleeps, locks r->l again */
|
||||
extern int rsleept(Rendez*, uint32_t); /* unlocks r->l, sleeps (up to ms), locks r->l again (if not timedout) */
|
||||
extern int rwakeup(Rendez*);
|
||||
extern int rwakeupall(Rendez*);
|
||||
extern void** privalloc(void);
|
||||
extern void privfree(void**);
|
||||
|
||||
/*
|
||||
* network dialing
|
||||
*/
|
||||
#define NETPATHLEN 40
|
||||
extern int accept(int, const char*);
|
||||
extern int announce(const char*, char*);
|
||||
extern int dial(const char*, const char*, char*, int*);
|
||||
extern void setnetmtpt(char*, int, const char*);
|
||||
extern int hangup(int);
|
||||
extern int listen(const char*, char*);
|
||||
extern char* netmkaddr(const char*, const char*, const char*);
|
||||
extern int reject(int, const char*, const char*);
|
||||
|
||||
/*
|
||||
* encryption
|
||||
*/
|
||||
extern int pushssl(int, const char*, const char*, const char*, int*);
|
||||
extern int pushtls(int, const char*, const char*, int, const char*,
|
||||
char*);
|
||||
|
||||
/*
|
||||
* network services
|
||||
*/
|
||||
typedef struct NetConnInfo NetConnInfo;
|
||||
struct NetConnInfo
|
||||
{
|
||||
char *dir; /* connection directory */
|
||||
char *root; /* network root */
|
||||
char *spec; /* binding spec */
|
||||
char *lsys; /* local system */
|
||||
char *lserv; /* local service */
|
||||
char *rsys; /* remote system */
|
||||
char *rserv; /* remote service */
|
||||
char *laddr; /* local address */
|
||||
char *raddr; /* remote address */
|
||||
};
|
||||
extern NetConnInfo* getnetconninfo(const char*, int);
|
||||
extern void freenetconninfo(NetConnInfo*);
|
||||
|
||||
/*
|
||||
* system calls
|
||||
*
|
||||
*/
|
||||
#define STATMAX 65535U /* max length of machine-independent stat structure */
|
||||
#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
|
||||
#define ERRMAX 128 /* max length of error string */
|
||||
|
||||
#define MORDER 0x0003 /* mask for bits defining order of mounting */
|
||||
#define MREPL 0x0000 /* mount replaces object */
|
||||
#define MBEFORE 0x0001 /* mount goes before others in union directory */
|
||||
#define MAFTER 0x0002 /* mount goes after others in union directory */
|
||||
#define MCREATE 0x0004 /* permit creation in mounted directory */
|
||||
#define MCACHE 0x0010 /* cache some data */
|
||||
#define MMASK 0x0017 /* all bits on */
|
||||
|
||||
#define OREAD 0 /* open for read */
|
||||
#define OWRITE 1 /* write */
|
||||
#define ORDWR 2 /* read and write */
|
||||
#define OEXEC 3 /* execute, == read but check execute permission */
|
||||
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
|
||||
#define OCEXEC 32 /* or'ed in, close on exec */
|
||||
#define ORCLOSE 64 /* or'ed in, remove on close */
|
||||
#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
|
||||
// #define OBEHIND 0x2000 /* use write behind for writes [for 9n] */
|
||||
|
||||
#define AEXIST 0 /* accessible: exists */
|
||||
#define AEXEC 1 /* execute access */
|
||||
#define AWRITE 2 /* write access */
|
||||
#define AREAD 4 /* read access */
|
||||
|
||||
/* Segattch */
|
||||
#define SG_RONLY 0040 /* read only */
|
||||
#define SG_CEXEC 0100 /* detach on exec */
|
||||
|
||||
#define NCONT 0 /* continue after note */
|
||||
#define NDFLT 1 /* terminate after note */
|
||||
#define NSAVE 2 /* clear note but hold state */
|
||||
#define NRSTR 3 /* restore saved state */
|
||||
|
||||
/* bits in Qid.type */
|
||||
#define QTDIR 0x80 /* type bit for directories */
|
||||
#define QTAPPEND 0x40 /* type bit for append only files */
|
||||
#define QTEXCL 0x20 /* type bit for exclusive use files */
|
||||
#define QTMOUNT 0x10 /* type bit for mounted channel */
|
||||
#define QTAUTH 0x08 /* type bit for authentication file */
|
||||
#define QTTMP 0x04 /* type bit for not-backed-up file */
|
||||
#define QTFILE 0x00 /* plain file */
|
||||
|
||||
/* bits in Dir.mode */
|
||||
#define DMDIR 0x80000000 /* mode bit for directories */
|
||||
#define DMAPPEND 0x40000000 /* mode bit for append only files */
|
||||
#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
|
||||
#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
|
||||
#define DMAUTH 0x08000000 /* mode bit for authentication file */
|
||||
#define DMTMP 0x04000000 /* mode bit for non-backed-up files */
|
||||
#define DMREAD 0x4 /* mode bit for read permission */
|
||||
#define DMWRITE 0x2 /* mode bit for write permission */
|
||||
#define DMEXEC 0x1 /* mode bit for execute permission */
|
||||
|
||||
/* rfork */
|
||||
enum
|
||||
{
|
||||
RFNAMEG = (1<<0),
|
||||
RFENVG = (1<<1),
|
||||
RFFDG = (1<<2),
|
||||
RFNOTEG = (1<<3),
|
||||
RFPROC = (1<<4),
|
||||
RFMEM = (1<<5),
|
||||
RFNOWAIT = (1<<6),
|
||||
RFCNAMEG = (1<<10),
|
||||
RFCENVG = (1<<11),
|
||||
RFCFDG = (1<<12),
|
||||
RFREND = (1<<13),
|
||||
RFNOMNT = (1<<14)
|
||||
};
|
||||
|
||||
typedef
|
||||
struct Qid
|
||||
{
|
||||
uint64_t path;
|
||||
uint32_t vers;
|
||||
uint8_t type;
|
||||
} Qid;
|
||||
|
||||
typedef
|
||||
struct Dir {
|
||||
/* system-modified data */
|
||||
uint16_t type; /* server type */
|
||||
uint dev; /* server subtype */
|
||||
/* file data */
|
||||
Qid qid; /* unique id from server */
|
||||
uint32_t mode; /* permissions */
|
||||
uint32_t atime; /* last read time */
|
||||
uint32_t mtime; /* last write time */
|
||||
int64_t length; /* file length */
|
||||
char *name; /* last element of path */
|
||||
char *uid; /* owner name */
|
||||
char *gid; /* group name */
|
||||
char *muid; /* last modifier name */
|
||||
} Dir;
|
||||
|
||||
/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
|
||||
typedef
|
||||
struct Waitmsg
|
||||
{
|
||||
int pid; /* of loved one */
|
||||
uint32_t time[3]; /* of loved one & descendants */
|
||||
char *msg;
|
||||
} Waitmsg;
|
||||
|
||||
typedef
|
||||
struct IOchunk
|
||||
{
|
||||
void *addr;
|
||||
uint32_t len;
|
||||
} IOchunk;
|
||||
|
||||
extern void _exits(const char*);
|
||||
|
||||
extern int access(const char*, int);
|
||||
extern int64_t alarm(uint64_t);
|
||||
extern int await(char*, int);
|
||||
extern int64_t awake(int64_t);
|
||||
extern int awakened(int64_t);
|
||||
extern int bind(const char*, const char*, int);
|
||||
extern int brk(void*);
|
||||
extern int chdir(const char*);
|
||||
extern int close(int);
|
||||
extern int create(const char*, int, uint32_t);
|
||||
extern int dup(int, int);
|
||||
extern int errstr(char*, uint);
|
||||
extern int exec(const char*, char* const[]);
|
||||
extern int execl(const char*, ...);
|
||||
extern int forgivewkp(int64_t);
|
||||
extern int fork(void);
|
||||
extern int rfork(int);
|
||||
extern int fauth(int, const char*);
|
||||
extern int fstat(int, uint8_t*, int);
|
||||
extern int fwstat(int, uint8_t*, int);
|
||||
extern int fversion(int, int, char*, int);
|
||||
extern int mount(int, int, const char*, int, const char*, int);
|
||||
extern int unmount(const char*, const char*);
|
||||
extern int noted(int);
|
||||
extern int notify(void(*)(void*, char*));
|
||||
extern int open(const char*, int);
|
||||
extern int fd2path(int, char*, int);
|
||||
// extern int fdflush(int);
|
||||
extern int pipe(int*);
|
||||
extern int32_t pread(int, void*, int32_t, int64_t);
|
||||
extern int32_t preadv(int, IOchunk*, int, int64_t);
|
||||
extern int32_t pwrite(int, const void*, int32_t, int64_t);
|
||||
extern int32_t pwritev(int, IOchunk*, int, int64_t);
|
||||
extern int32_t read(int, void*, int32_t);
|
||||
extern int32_t readn(int, void*, int32_t);
|
||||
extern int32_t readv(int, IOchunk*, int);
|
||||
extern int remove(const char*);
|
||||
extern void* sbrk(uint32_t);
|
||||
extern int32_t oseek(int, int32_t, int);
|
||||
extern int64_t seek(int, int64_t, int);
|
||||
extern void* segattach(int, const char*, void*, uint32_t);
|
||||
extern void* segbrk(void*, void*);
|
||||
extern int segdetach(void*);
|
||||
extern int segflush(void*, uint32_t);
|
||||
extern int segfree(void*, uint32_t);
|
||||
extern int semacquire(int32_t*, int);
|
||||
extern int32_t semrelease(int32_t*, int32_t);
|
||||
extern void sleep(int32_t);
|
||||
extern int stat(const char*, uint8_t*, int);
|
||||
extern int tsemacquire(int32_t*, uint64_t);
|
||||
extern Waitmsg* wait(void);
|
||||
extern int waitpid(void);
|
||||
extern int32_t write(int, const void*, int32_t);
|
||||
extern int32_t writev(int, IOchunk*, int);
|
||||
extern int wstat(const char*, uint8_t*, int);
|
||||
extern void* rendezvous(void*, void*);
|
||||
|
||||
extern Dir* dirstat(const char*);
|
||||
extern Dir* dirfstat(int);
|
||||
extern int dirwstat(const char*, Dir*);
|
||||
extern int dirfwstat(int, Dir*);
|
||||
extern int32_t dirread(int, Dir**);
|
||||
extern void nulldir(Dir*);
|
||||
extern int32_t dirreadall(int, Dir**);
|
||||
extern int getpid(void);
|
||||
extern int getppid(void);
|
||||
extern void rerrstr(char*, uint);
|
||||
extern char* sysname(void);
|
||||
extern void werrstr(const char*, ...);
|
||||
#pragma varargck argpos werrstr 1
|
||||
|
||||
/* compiler directives on plan 9 */
|
||||
#define SET(x) ((x)=0)
|
||||
#define USED(x) if(x){}else{}
|
||||
#ifdef __GNUC__
|
||||
# if __GNUC__ >= 3
|
||||
# undef USED
|
||||
# define USED(x) ((void)(x))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern char *argv0;
|
||||
/* #define ARGBEGIN for((argv0||(argv0=*argv)),argv++,argc--;\ */
|
||||
#define ARGBEGIN for((argv0?0:(argv0=*argv)),argv++,argc--;\
|
||||
argv[0] && argv[0][0]=='-' && argv[0][1];\
|
||||
argc--, argv++) {\
|
||||
char *_args, *_argt;\
|
||||
Rune _argc;\
|
||||
_args = &argv[0][1];\
|
||||
if(_args[0]=='-' && _args[1]==0){\
|
||||
argc--; argv++; break;\
|
||||
}\
|
||||
_argc = 0;\
|
||||
while(*_args && (_args += chartorune(&_argc, _args)))\
|
||||
switch(_argc)
|
||||
/* #define ARGEND SET(_argt);USED(_argt,_argc,_args);}USED(argv, argc); */
|
||||
#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
|
||||
#define ARGF() (_argt=_args, _args="",\
|
||||
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
|
||||
#define EARGF(x) (_argt=_args, _args="",\
|
||||
(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), argc = *(int*)0, (char*)0)))
|
||||
|
||||
#define ARGC() _argc
|
||||
|
||||
/* this is used by sbrk and brk, it's a really bad idea to redefine it */
|
||||
extern char end[];
|
||||
|
64
sys/include/pool.h
Normal file
64
sys/include/pool.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
typedef struct Pool Pool;
|
||||
struct Pool {
|
||||
char* name;
|
||||
uint32_t maxsize;
|
||||
|
||||
uint32_t cursize;
|
||||
uint32_t curfree;
|
||||
uint32_t curalloc;
|
||||
|
||||
uint32_t minarena; /* smallest size of new arena */
|
||||
uint32_t quantum; /* allocated blocks should be multiple of */
|
||||
uint32_t minblock; /* smallest newly allocated block */
|
||||
|
||||
void* freeroot; /* actually Free* */
|
||||
void* arenalist; /* actually Arena* */
|
||||
|
||||
void* (*alloc)(uint32_t);
|
||||
int (*merge)(void*, void*);
|
||||
void (*move)(void* from, void* to);
|
||||
|
||||
int flags;
|
||||
int nfree;
|
||||
int lastcompact;
|
||||
|
||||
void (*lock)(Pool*);
|
||||
void (*unlock)(Pool*);
|
||||
void (*print)(Pool*, char*, ...);
|
||||
void (*panic)(Pool*, char*, ...);
|
||||
void (*logstack)(Pool*);
|
||||
|
||||
void* private;
|
||||
};
|
||||
|
||||
extern void* poolalloc(Pool*, uint32_t);
|
||||
extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t,
|
||||
uint32_t);
|
||||
extern void poolfree(Pool*, void*);
|
||||
extern uint32_t poolmsize(Pool*, void*);
|
||||
extern void* poolrealloc(Pool*, void*, uint32_t);
|
||||
extern void poolcheck(Pool*);
|
||||
extern int poolcompact(Pool*);
|
||||
extern void poolblockcheck(Pool*, void*);
|
||||
|
||||
extern Pool* mainmem;
|
||||
extern Pool* imagmem;
|
||||
|
||||
enum { /* flags */
|
||||
POOL_ANTAGONISM = 1<<0,
|
||||
POOL_PARANOIA = 1<<1,
|
||||
POOL_VERBOSITY = 1<<2,
|
||||
POOL_DEBUGGING = 1<<3,
|
||||
POOL_LOGGING = 1<<4,
|
||||
POOL_TOLERANCE = 1<<5,
|
||||
POOL_NOREUSE = 1<<6,
|
||||
};
|
29
sys/include/tos.h
Normal file
29
sys/include/tos.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
typedef struct Tos Tos;
|
||||
|
||||
struct Tos {
|
||||
uint64_t cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */
|
||||
int64_t kcycles; /* cycles spent in kernel */
|
||||
int64_t pcycles; /* cycles spent in process (kernel + user) */
|
||||
uint32_t pid; /* might as well put the pid here */
|
||||
uint32_t clock;
|
||||
/* scratch space for kernel use (e.g., mips fp delay-slot execution) */
|
||||
uint32_t kscr[4];
|
||||
|
||||
/*
|
||||
* Fields below are not available on Plan 9 kernels.
|
||||
*/
|
||||
int nixtype; /* role of the core we are running at */
|
||||
int core; /* core we are running at */
|
||||
/* top of stack is here */
|
||||
};
|
||||
|
||||
extern Tos *_tos;
|
32
sys/src/klib.json
Normal file
32
sys/src/klib.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"KernelLibs": {
|
||||
"Cflags": [
|
||||
"-std=c11",
|
||||
"-c",
|
||||
"-I/$JEHANNE/arch/$ARCH/include",
|
||||
"-I/$JEHANNE/sys/include",
|
||||
"-I.",
|
||||
"-mcmodel=kernel",
|
||||
"-O0",
|
||||
"-fplan9-extensions",
|
||||
"-mno-red-zone",
|
||||
"-ffreestanding",
|
||||
"-fno-builtin",
|
||||
"-Wall",
|
||||
"-Wno-missing-braces",
|
||||
"-Wno-parentheses",
|
||||
"-Wno-unknown-pragmas",
|
||||
"-Wuninitialized",
|
||||
"-g"
|
||||
],
|
||||
"Oflags": [
|
||||
"-static"
|
||||
],
|
||||
"Post": [
|
||||
"rm *.o"
|
||||
],
|
||||
"Pre": [
|
||||
"rm -f *.o *.tag.*"
|
||||
]
|
||||
}
|
||||
}
|
7
sys/src/klibs.json
Normal file
7
sys/src/klibs.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"klibs": {
|
||||
"Projects": [
|
||||
"/sys/src/libc/klibc.json"
|
||||
]
|
||||
}
|
||||
}
|
16
sys/src/lib.json
Normal file
16
sys/src/lib.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"Libs": {
|
||||
"Include": [
|
||||
"/arch/$ARCH/include/cflags.json"
|
||||
],
|
||||
"Oflags": [
|
||||
"-static"
|
||||
],
|
||||
"Post": [
|
||||
"rm *.o"
|
||||
],
|
||||
"Pre": [
|
||||
"rm -f *.o *.tag.*"
|
||||
]
|
||||
}
|
||||
}
|
42
sys/src/libc/9sys/access.c
Normal file
42
sys/src/libc/9sys/access.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
access(const char *name, int mode)
|
||||
{
|
||||
int fd;
|
||||
Dir *db;
|
||||
static char omode[] = {
|
||||
0,
|
||||
OEXEC,
|
||||
OWRITE,
|
||||
ORDWR,
|
||||
OREAD,
|
||||
OEXEC, /* only approximate */
|
||||
ORDWR,
|
||||
ORDWR /* only approximate */
|
||||
};
|
||||
|
||||
if(mode == AEXIST){
|
||||
db = dirstat(name);
|
||||
free(db);
|
||||
if(db != nil)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
fd = open(name, omode[mode&7]);
|
||||
if(fd >= 0){
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
284
sys/src/libc/9sys/announce.c
Normal file
284
sys/src/libc/9sys/announce.c
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int nettrans(const char*, char*, int na, char*, int);
|
||||
|
||||
enum
|
||||
{
|
||||
Maxpath= 256,
|
||||
};
|
||||
|
||||
/*
|
||||
* announce a network service.
|
||||
*/
|
||||
int
|
||||
announce(const char *addr, char *dir)
|
||||
{
|
||||
int ctl, n, m;
|
||||
char buf[Maxpath];
|
||||
char buf2[Maxpath];
|
||||
char netdir[Maxpath];
|
||||
char naddr[Maxpath];
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* translate the address
|
||||
*/
|
||||
if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* get a control channel
|
||||
*/
|
||||
ctl = open(netdir, ORDWR);
|
||||
if(ctl<0){
|
||||
werrstr("announce opening %s: %r", netdir);
|
||||
return -1;
|
||||
}
|
||||
cp = strrchr(netdir, '/');
|
||||
if(cp == nil){
|
||||
werrstr("announce arg format %s", netdir);
|
||||
close(ctl);
|
||||
return -1;
|
||||
}
|
||||
*cp = 0;
|
||||
|
||||
/*
|
||||
* find out which line we have
|
||||
*/
|
||||
n = snprint(buf, sizeof(buf), "%s/", netdir);
|
||||
m = read(ctl, &buf[n], sizeof(buf)-n-1);
|
||||
if(m <= 0){
|
||||
werrstr("announce reading %s: %r", netdir);
|
||||
close(ctl);
|
||||
return -1;
|
||||
}
|
||||
buf[n+m] = 0;
|
||||
|
||||
/*
|
||||
* make the call
|
||||
*/
|
||||
n = snprint(buf2, sizeof(buf2), "announce %s", naddr);
|
||||
if(write(ctl, buf2, n)!=n){
|
||||
werrstr("announce writing %s: %r", netdir);
|
||||
close(ctl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* return directory etc.
|
||||
*/
|
||||
if(dir){
|
||||
strncpy(dir, buf, NETPATHLEN);
|
||||
dir[NETPATHLEN-1] = 0;
|
||||
}
|
||||
return ctl;
|
||||
}
|
||||
|
||||
/*
|
||||
* listen for an incoming call
|
||||
*/
|
||||
int
|
||||
listen(const char *dir, char *newdir)
|
||||
{
|
||||
int ctl, n, m;
|
||||
char buf[Maxpath];
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* open listen, wait for a call
|
||||
*/
|
||||
snprint(buf, sizeof(buf), "%s/listen", dir);
|
||||
ctl = open(buf, ORDWR);
|
||||
if(ctl < 0){
|
||||
werrstr("listen opening %s: %r", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find out which line we have
|
||||
*/
|
||||
strncpy(buf, dir, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
cp = strrchr(buf, '/');
|
||||
if(cp == nil){
|
||||
close(ctl);
|
||||
werrstr("listen arg format %s", dir);
|
||||
return -1;
|
||||
}
|
||||
*++cp = 0;
|
||||
n = cp-buf;
|
||||
m = read(ctl, cp, sizeof(buf) - n - 1);
|
||||
if(m <= 0){
|
||||
close(ctl);
|
||||
werrstr("listen reading %s/listen: %r", dir);
|
||||
return -1;
|
||||
}
|
||||
buf[n+m] = 0;
|
||||
|
||||
/*
|
||||
* return directory etc.
|
||||
*/
|
||||
if(newdir){
|
||||
strncpy(newdir, buf, NETPATHLEN);
|
||||
newdir[NETPATHLEN-1] = 0;
|
||||
}
|
||||
return ctl;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* accept a call, return an fd to the open data file
|
||||
*/
|
||||
int
|
||||
accept(int ctl, const char *dir)
|
||||
{
|
||||
char buf[Maxpath];
|
||||
const char *num;
|
||||
int32_t n;
|
||||
|
||||
num = strrchr(dir, '/');
|
||||
if(num == nil)
|
||||
num = dir;
|
||||
else
|
||||
num++;
|
||||
|
||||
n = snprint(buf, sizeof(buf), "accept %s", num);
|
||||
write(ctl, buf, n); /* ignore return value, network might not need accepts */
|
||||
|
||||
snprint(buf, sizeof(buf), "%s/data", dir);
|
||||
return open(buf, ORDWR);
|
||||
}
|
||||
|
||||
/*
|
||||
* reject a call, tell device the reason for the rejection
|
||||
*/
|
||||
int
|
||||
reject(int ctl, const char *dir, const char *cause)
|
||||
{
|
||||
char buf[Maxpath];
|
||||
const char *num;
|
||||
int32_t n;
|
||||
|
||||
num = strrchr(dir, '/');
|
||||
if(num == 0)
|
||||
num = dir;
|
||||
else
|
||||
num++;
|
||||
snprint(buf, sizeof(buf), "reject %s %s", num, cause);
|
||||
n = strlen(buf);
|
||||
if(write(ctl, buf, n) != n)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* perform the identity translation (in case we can't reach cs)
|
||||
*/
|
||||
static int
|
||||
identtrans(char *netdir, const char *addr, char *naddr, int na,
|
||||
char *file, int nf)
|
||||
{
|
||||
char proto[Maxpath];
|
||||
char *p;
|
||||
|
||||
USED(nf);
|
||||
|
||||
/* parse the protocol */
|
||||
strncpy(proto, addr, sizeof(proto));
|
||||
proto[sizeof(proto)-1] = 0;
|
||||
p = strchr(proto, '!');
|
||||
if(p)
|
||||
*p++ = 0;
|
||||
|
||||
snprint(file, nf, "%s/%s/clone", netdir, proto);
|
||||
strncpy(naddr, p, na);
|
||||
naddr[na-1] = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* call up the connection server and get a translation
|
||||
*/
|
||||
static int
|
||||
nettrans(const char *addr, char *naddr, int na, char *file, int nf)
|
||||
{
|
||||
int i, fd;
|
||||
char buf[Maxpath];
|
||||
char netdir[Maxpath];
|
||||
char *p, *p2;
|
||||
int32_t n;
|
||||
|
||||
/*
|
||||
* parse, get network directory
|
||||
*/
|
||||
p = strchr(addr, '!');
|
||||
if(p == 0){
|
||||
werrstr("bad dial string: %s", addr);
|
||||
return -1;
|
||||
}
|
||||
if(*addr != '/'){
|
||||
strncpy(netdir, "/net", sizeof(netdir));
|
||||
netdir[sizeof(netdir) - 1] = 0;
|
||||
} else {
|
||||
for(p2 = p; *p2 != '/'; p2--)
|
||||
;
|
||||
i = p2 - addr;
|
||||
if(i == 0 || i >= sizeof(netdir)){
|
||||
werrstr("bad dial string: %s", addr);
|
||||
return -1;
|
||||
}
|
||||
strncpy(netdir, addr, i);
|
||||
netdir[i] = 0;
|
||||
addr = p2 + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ask the connection server
|
||||
*/
|
||||
snprint(buf, sizeof(buf), "%s/cs", netdir);
|
||||
fd = open(buf, ORDWR);
|
||||
if(fd < 0)
|
||||
return identtrans(netdir, addr, naddr, na, file, nf);
|
||||
if(write(fd, addr, strlen(addr)) < 0){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
seek(fd, 0, 0);
|
||||
n = read(fd, buf, sizeof(buf)-1);
|
||||
close(fd);
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
buf[n] = 0;
|
||||
|
||||
/*
|
||||
* parse the reply
|
||||
*/
|
||||
p = strchr(buf, ' ');
|
||||
if(p == 0)
|
||||
return -1;
|
||||
*p++ = 0;
|
||||
strncpy(naddr, p, na);
|
||||
naddr[na-1] = 0;
|
||||
|
||||
if(buf[0] == '/'){
|
||||
p = strchr(buf+1, '/');
|
||||
if(p == nil)
|
||||
p = buf;
|
||||
else
|
||||
p++;
|
||||
}
|
||||
snprint(file, nf, "%s/%s", netdir, p);
|
||||
return 0;
|
||||
}
|
50
sys/src/libc/9sys/awakened.c
Normal file
50
sys/src/libc/9sys/awakened.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* Jehanne is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* Jehanne is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
awakened(int64_t wakeup)
|
||||
{
|
||||
/* awake returns the ticks of the scheduled wakeup in negative,
|
||||
* thus a wakeup is in the past iff (-awake(0)) >= (-wakeup)
|
||||
*
|
||||
* NOTE: this is not a macro so that we can change the awake()
|
||||
* implementation in the future, without affecting the client code.
|
||||
*/
|
||||
assert(wakeup < 0);
|
||||
return wakeup >= awake(0);
|
||||
}
|
||||
|
||||
int
|
||||
forgivewkp(int64_t wakeup)
|
||||
{
|
||||
/* awake returns the ticks of the scheduled wakeup in negative,
|
||||
* and is able to remove a wakeup provided such value.
|
||||
*
|
||||
* forgivewkp() is just a wrapper to hide awake()'s details that
|
||||
* could change in the future and make client code easier to
|
||||
* read.
|
||||
*
|
||||
* NOTE: this is not a macro so that we can change the awake()
|
||||
* implementation in the future, without affecting the client code.
|
||||
*/
|
||||
assert(wakeup < 0);
|
||||
return awake(wakeup);
|
||||
}
|
104
sys/src/libc/9sys/convD2M.c
Normal file
104
sys/src/libc/9sys/convD2M.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
uint
|
||||
sizeD2M(Dir *d)
|
||||
{
|
||||
char *sv[4];
|
||||
int i, ns;
|
||||
|
||||
sv[0] = d->name;
|
||||
sv[1] = d->uid;
|
||||
sv[2] = d->gid;
|
||||
sv[3] = d->muid;
|
||||
|
||||
ns = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
if(sv[i])
|
||||
ns += strlen(sv[i]);
|
||||
|
||||
return STATFIXLEN + ns;
|
||||
}
|
||||
|
||||
uint
|
||||
convD2M(Dir *d, uint8_t *buf, uint nbuf)
|
||||
{
|
||||
uint8_t *p, *ebuf;
|
||||
char *sv[4];
|
||||
int i, ns, nsv[4], ss;
|
||||
|
||||
if(nbuf < BIT16SZ)
|
||||
return 0;
|
||||
|
||||
p = buf;
|
||||
ebuf = buf + nbuf;
|
||||
|
||||
sv[0] = d->name;
|
||||
sv[1] = d->uid;
|
||||
sv[2] = d->gid;
|
||||
sv[3] = d->muid;
|
||||
|
||||
ns = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
if(sv[i])
|
||||
nsv[i] = strlen(sv[i]);
|
||||
else
|
||||
nsv[i] = 0;
|
||||
ns += nsv[i];
|
||||
}
|
||||
|
||||
ss = STATFIXLEN + ns;
|
||||
|
||||
/* set size before erroring, so user can know how much is needed */
|
||||
/* note that length excludes count field itself */
|
||||
PBIT16(p, ss-BIT16SZ);
|
||||
p += BIT16SZ;
|
||||
|
||||
if(ss > nbuf)
|
||||
return BIT16SZ;
|
||||
|
||||
PBIT16(p, d->type);
|
||||
p += BIT16SZ;
|
||||
PBIT32(p, d->dev);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, d->qid.type);
|
||||
p += BIT8SZ;
|
||||
PBIT32(p, d->qid.vers);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, d->qid.path);
|
||||
p += BIT64SZ;
|
||||
PBIT32(p, d->mode);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, d->atime);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, d->mtime);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, d->length);
|
||||
p += BIT64SZ;
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
ns = nsv[i];
|
||||
if(p + ns + BIT16SZ > ebuf)
|
||||
return 0;
|
||||
PBIT16(p, ns);
|
||||
p += BIT16SZ;
|
||||
if(ns)
|
||||
memmove(p, sv[i], ns);
|
||||
p += ns;
|
||||
}
|
||||
|
||||
if(ss != p - buf)
|
||||
return 0;
|
||||
|
||||
return p - buf;
|
||||
}
|
103
sys/src/libc/9sys/convM2D.c
Normal file
103
sys/src/libc/9sys/convM2D.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
statcheck(uint8_t *buf, uint nbuf)
|
||||
{
|
||||
uint8_t *ebuf;
|
||||
int i;
|
||||
|
||||
ebuf = buf + nbuf;
|
||||
|
||||
if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
|
||||
return -1;
|
||||
|
||||
buf += STATFIXLEN - 4 * BIT16SZ;
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
if(buf + BIT16SZ > ebuf)
|
||||
return -1;
|
||||
buf += BIT16SZ + GBIT16(buf);
|
||||
}
|
||||
|
||||
if(buf != ebuf)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char nullstring[] = "";
|
||||
|
||||
uint
|
||||
convM2D(uint8_t *buf, uint nbuf, Dir *d, char *strs)
|
||||
{
|
||||
uint8_t *p, *ebuf;
|
||||
char *sv[4];
|
||||
int i, ns;
|
||||
|
||||
if(nbuf < STATFIXLEN)
|
||||
return 0;
|
||||
|
||||
p = buf;
|
||||
ebuf = buf + nbuf;
|
||||
|
||||
p += BIT16SZ; /* ignore size */
|
||||
d->type = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
d->dev = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->qid.type = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
d->qid.vers = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->qid.path = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
d->mode = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->atime = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->mtime = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->length = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
if(p + BIT16SZ > ebuf)
|
||||
return 0;
|
||||
ns = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(p + ns > ebuf)
|
||||
return 0;
|
||||
if(strs){
|
||||
sv[i] = strs;
|
||||
memmove(strs, p, ns);
|
||||
strs += ns;
|
||||
*strs++ = '\0';
|
||||
}
|
||||
p += ns;
|
||||
}
|
||||
|
||||
if(strs){
|
||||
d->name = sv[0];
|
||||
d->uid = sv[1];
|
||||
d->gid = sv[2];
|
||||
d->muid = sv[3];
|
||||
}else{
|
||||
d->name = nullstring;
|
||||
d->uid = nullstring;
|
||||
d->gid = nullstring;
|
||||
d->muid = nullstring;
|
||||
}
|
||||
|
||||
return p - buf;
|
||||
}
|
324
sys/src/libc/9sys/convM2S.c
Normal file
324
sys/src/libc/9sys/convM2S.c
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static
|
||||
uint8_t*
|
||||
gstring(uint8_t *p, uint8_t *ep, char **s)
|
||||
{
|
||||
uint n;
|
||||
|
||||
if(p+BIT16SZ > ep)
|
||||
return nil;
|
||||
n = GBIT16(p);
|
||||
p += BIT16SZ - 1;
|
||||
if(p+n+1 > ep)
|
||||
return nil;
|
||||
/* move it down, on top of count, to make room for '\0' */
|
||||
memmove(p, p + 1, n);
|
||||
p[n] = '\0';
|
||||
*s = (char*)p;
|
||||
p += n+1;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
uint8_t*
|
||||
gqid(uint8_t *p, uint8_t *ep, Qid *q)
|
||||
{
|
||||
if(p+QIDSZ > ep)
|
||||
return nil;
|
||||
q->type = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
q->vers = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
q->path = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* no syntactic checks.
|
||||
* three causes for error:
|
||||
* 1. message size field is incorrect
|
||||
* 2. input buffer too short for its own data (counts too long, etc.)
|
||||
* 3. too many names or qids
|
||||
* gqid() and gstring() return nil if they would reach beyond buffer.
|
||||
* main switch statement checks range and also can fall through
|
||||
* to test at end of routine.
|
||||
*/
|
||||
uint
|
||||
convM2S(uint8_t *ap, uint nap, Fcall *f)
|
||||
{
|
||||
uint8_t *p, *ep;
|
||||
uint i, size;
|
||||
|
||||
p = ap;
|
||||
ep = p + nap;
|
||||
|
||||
if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
|
||||
return 0;
|
||||
size = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
|
||||
if(size < BIT32SZ+BIT8SZ+BIT16SZ)
|
||||
return 0;
|
||||
|
||||
f->type = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
f->tag = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
|
||||
switch(f->type)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case Tversion:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->msize = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->version);
|
||||
break;
|
||||
|
||||
case Tflush:
|
||||
if(p+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->oldtag = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
break;
|
||||
|
||||
case Tauth:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->afid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->uname);
|
||||
if(p == nil)
|
||||
break;
|
||||
p = gstring(p, ep, &f->aname);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Tattach:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->afid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->uname);
|
||||
if(p == nil)
|
||||
break;
|
||||
p = gstring(p, ep, &f->aname);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Twalk:
|
||||
if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->newfid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->nwname = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(f->nwname > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwname; i++){
|
||||
p = gstring(p, ep, &f->wname[i]);
|
||||
if(p == nil)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Topen:
|
||||
if(p+BIT32SZ+BIT8SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->mode = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tcreate:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->name);
|
||||
if(p == nil)
|
||||
break;
|
||||
if(p+BIT32SZ+BIT8SZ > ep)
|
||||
return 0;
|
||||
f->perm = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->mode = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tread:
|
||||
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->offset = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twrite:
|
||||
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->offset = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(p+f->count > ep)
|
||||
return 0;
|
||||
f->data = (char*)p;
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Tclunk:
|
||||
case Tremove:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Tstat:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twstat:
|
||||
if(p+BIT32SZ+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->nstat = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(p+f->nstat > ep)
|
||||
return 0;
|
||||
f->stat = p;
|
||||
p += f->nstat;
|
||||
break;
|
||||
|
||||
/*
|
||||
*/
|
||||
case Rversion:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->msize = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->version);
|
||||
break;
|
||||
|
||||
case Rerror:
|
||||
p = gstring(p, ep, &f->ename);
|
||||
break;
|
||||
|
||||
case Rflush:
|
||||
break;
|
||||
|
||||
case Rauth:
|
||||
p = gqid(p, ep, &f->aqid);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Rattach:
|
||||
p = gqid(p, ep, &f->qid);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Rwalk:
|
||||
if(p+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->nwqid = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(f->nwqid > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwqid; i++){
|
||||
p = gqid(p, ep, &f->wqid[i]);
|
||||
if(p == nil)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Ropen:
|
||||
case Rcreate:
|
||||
p = gqid(p, ep, &f->qid);
|
||||
if(p == nil)
|
||||
break;
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->iounit = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rread:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(p+f->count > ep)
|
||||
return 0;
|
||||
f->data = (char*)p;
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Rwrite:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rclunk:
|
||||
case Rremove:
|
||||
break;
|
||||
|
||||
case Rstat:
|
||||
if(p+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->nstat = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(p+f->nstat > ep)
|
||||
return 0;
|
||||
f->stat = p;
|
||||
p += f->nstat;
|
||||
break;
|
||||
|
||||
case Rwstat:
|
||||
break;
|
||||
}
|
||||
|
||||
if(p==nil || p>ep)
|
||||
return 0;
|
||||
if(ap+size == p)
|
||||
return size;
|
||||
return 0;
|
||||
}
|
398
sys/src/libc/9sys/convS2M.c
Normal file
398
sys/src/libc/9sys/convS2M.c
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static
|
||||
uint8_t*
|
||||
pstring(uint8_t *p, char *s)
|
||||
{
|
||||
uint n;
|
||||
|
||||
if(s == nil){
|
||||
PBIT16(p, 0);
|
||||
p += BIT16SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
n = strlen(s);
|
||||
/*
|
||||
* We are moving the string before the length,
|
||||
* so you can S2M a struct into an existing message
|
||||
*/
|
||||
memmove(p + BIT16SZ, s, n);
|
||||
PBIT16(p, n);
|
||||
p += n + BIT16SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
uint8_t*
|
||||
pqid(uint8_t *p, Qid *q)
|
||||
{
|
||||
PBIT8(p, q->type);
|
||||
p += BIT8SZ;
|
||||
PBIT32(p, q->vers);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, q->path);
|
||||
p += BIT64SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
uint
|
||||
stringsz(char *s)
|
||||
{
|
||||
if(s == nil)
|
||||
return BIT16SZ;
|
||||
|
||||
return BIT16SZ+strlen(s);
|
||||
}
|
||||
|
||||
uint
|
||||
sizeS2M(Fcall *f)
|
||||
{
|
||||
uint n;
|
||||
int i;
|
||||
|
||||
n = 0;
|
||||
n += BIT32SZ; /* size */
|
||||
n += BIT8SZ; /* type */
|
||||
n += BIT16SZ; /* tag */
|
||||
|
||||
switch(f->type)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case Tversion:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->version);
|
||||
break;
|
||||
|
||||
case Tflush:
|
||||
n += BIT16SZ;
|
||||
break;
|
||||
|
||||
case Tauth:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->uname);
|
||||
n += stringsz(f->aname);
|
||||
break;
|
||||
|
||||
case Tattach:
|
||||
n += BIT32SZ;
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->uname);
|
||||
n += stringsz(f->aname);
|
||||
break;
|
||||
|
||||
case Twalk:
|
||||
n += BIT32SZ;
|
||||
n += BIT32SZ;
|
||||
n += BIT16SZ;
|
||||
for(i=0; i<f->nwname; i++)
|
||||
n += stringsz(f->wname[i]);
|
||||
break;
|
||||
|
||||
case Topen:
|
||||
n += BIT32SZ;
|
||||
n += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tcreate:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->name);
|
||||
n += BIT32SZ;
|
||||
n += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tread:
|
||||
n += BIT32SZ;
|
||||
n += BIT64SZ;
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twrite:
|
||||
n += BIT32SZ;
|
||||
n += BIT64SZ;
|
||||
n += BIT32SZ;
|
||||
n += f->count;
|
||||
break;
|
||||
|
||||
case Tclunk:
|
||||
case Tremove:
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Tstat:
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twstat:
|
||||
n += BIT32SZ;
|
||||
n += BIT16SZ;
|
||||
n += f->nstat;
|
||||
break;
|
||||
/*
|
||||
*/
|
||||
|
||||
case Rversion:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->version);
|
||||
break;
|
||||
|
||||
case Rerror:
|
||||
n += stringsz(f->ename);
|
||||
break;
|
||||
|
||||
case Rflush:
|
||||
break;
|
||||
|
||||
case Rauth:
|
||||
n += QIDSZ;
|
||||
break;
|
||||
|
||||
case Rattach:
|
||||
n += QIDSZ;
|
||||
break;
|
||||
|
||||
case Rwalk:
|
||||
n += BIT16SZ;
|
||||
n += f->nwqid*QIDSZ;
|
||||
break;
|
||||
|
||||
case Ropen:
|
||||
case Rcreate:
|
||||
n += QIDSZ;
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rread:
|
||||
n += BIT32SZ;
|
||||
n += f->count;
|
||||
break;
|
||||
|
||||
case Rwrite:
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rclunk:
|
||||
break;
|
||||
|
||||
case Rremove:
|
||||
break;
|
||||
|
||||
case Rstat:
|
||||
n += BIT16SZ;
|
||||
n += f->nstat;
|
||||
break;
|
||||
|
||||
case Rwstat:
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
uint
|
||||
convS2M(Fcall *f, uint8_t *ap, uint nap)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint i, size;
|
||||
|
||||
size = sizeS2M(f);
|
||||
if(size == 0)
|
||||
return 0;
|
||||
if(size > nap)
|
||||
return 0;
|
||||
|
||||
p = (uint8_t*)ap;
|
||||
|
||||
PBIT32(p, size);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, f->type);
|
||||
p += BIT8SZ;
|
||||
PBIT16(p, f->tag);
|
||||
p += BIT16SZ;
|
||||
|
||||
switch(f->type)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case Tversion:
|
||||
PBIT32(p, f->msize);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->version);
|
||||
break;
|
||||
|
||||
case Tflush:
|
||||
PBIT16(p, f->oldtag);
|
||||
p += BIT16SZ;
|
||||
break;
|
||||
|
||||
case Tauth:
|
||||
PBIT32(p, f->afid);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->uname);
|
||||
p = pstring(p, f->aname);
|
||||
break;
|
||||
|
||||
case Tattach:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, f->afid);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->uname);
|
||||
p = pstring(p, f->aname);
|
||||
break;
|
||||
|
||||
case Twalk:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, f->newfid);
|
||||
p += BIT32SZ;
|
||||
PBIT16(p, f->nwname);
|
||||
p += BIT16SZ;
|
||||
if(f->nwname > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwname; i++)
|
||||
p = pstring(p, f->wname[i]);
|
||||
break;
|
||||
|
||||
case Topen:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, f->mode);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tcreate:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->name);
|
||||
PBIT32(p, f->perm);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, f->mode);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tread:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, f->offset);
|
||||
p += BIT64SZ;
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twrite:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, f->offset);
|
||||
p += BIT64SZ;
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
memmove(p, f->data, f->count);
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Tclunk:
|
||||
case Tremove:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Tstat:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twstat:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT16(p, f->nstat);
|
||||
p += BIT16SZ;
|
||||
memmove(p, f->stat, f->nstat);
|
||||
p += f->nstat;
|
||||
break;
|
||||
/*
|
||||
*/
|
||||
|
||||
case Rversion:
|
||||
PBIT32(p, f->msize);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->version);
|
||||
break;
|
||||
|
||||
case Rerror:
|
||||
p = pstring(p, f->ename);
|
||||
break;
|
||||
|
||||
case Rflush:
|
||||
break;
|
||||
|
||||
case Rauth:
|
||||
p = pqid(p, &f->aqid);
|
||||
break;
|
||||
|
||||
case Rattach:
|
||||
p = pqid(p, &f->qid);
|
||||
break;
|
||||
|
||||
case Rwalk:
|
||||
PBIT16(p, f->nwqid);
|
||||
p += BIT16SZ;
|
||||
if(f->nwqid > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwqid; i++)
|
||||
p = pqid(p, &f->wqid[i]);
|
||||
break;
|
||||
|
||||
case Ropen:
|
||||
case Rcreate:
|
||||
p = pqid(p, &f->qid);
|
||||
PBIT32(p, f->iounit);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rread:
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
memmove(p, f->data, f->count);
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Rwrite:
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rclunk:
|
||||
break;
|
||||
|
||||
case Rremove:
|
||||
break;
|
||||
|
||||
case Rstat:
|
||||
PBIT16(p, f->nstat);
|
||||
p += BIT16SZ;
|
||||
memmove(p, f->stat, f->nstat);
|
||||
p += f->nstat;
|
||||
break;
|
||||
|
||||
case Rwstat:
|
||||
break;
|
||||
}
|
||||
if(size != p-ap)
|
||||
return 0;
|
||||
return size;
|
||||
}
|
25
sys/src/libc/9sys/cputime.c
Normal file
25
sys/src/libc/9sys/cputime.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define HZ 1000
|
||||
|
||||
double
|
||||
cputime(void)
|
||||
{
|
||||
int32_t t[4];
|
||||
int i;
|
||||
|
||||
times(t);
|
||||
for(i=1; i<4; i++)
|
||||
t[0] += t[i];
|
||||
return t[0] / (double)HZ;
|
||||
}
|
316
sys/src/libc/9sys/ctime.c
Normal file
316
sys/src/libc/9sys/ctime.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This routine converts time as follows.
|
||||
* The epoch is 0000 Jan 1 1970 GMT.
|
||||
* The argument time is in seconds since then.
|
||||
* The localtime(t) entry returns a pointer to an array
|
||||
* containing
|
||||
*
|
||||
* seconds (0-59)
|
||||
* minutes (0-59)
|
||||
* hours (0-23)
|
||||
* day of month (1-31)
|
||||
* month (0-11)
|
||||
* year-1970
|
||||
* weekday (0-6, Sun is 0)
|
||||
* day of the year
|
||||
* daylight savings flag
|
||||
*
|
||||
* The routine gets the daylight savings time from the environment.
|
||||
*
|
||||
* asctime(tvec))
|
||||
* where tvec is produced by localtime
|
||||
* returns a ptr to a character string
|
||||
* that has the ascii time in the form
|
||||
*
|
||||
* \\
|
||||
* Thu Jan 01 00:00:00 GMT 1970n0
|
||||
* 012345678901234567890123456789
|
||||
* 0 1 2
|
||||
*
|
||||
* ctime(t) just calls localtime, then asctime.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static char dmsize[12] =
|
||||
{
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
/*
|
||||
* The following table is used for 1974 and 1975 and
|
||||
* gives the day number of the first day after the Sunday of the
|
||||
* change.
|
||||
*/
|
||||
|
||||
static int dysize(int);
|
||||
static void ct_numb(char*, int);
|
||||
|
||||
#define TZSIZE 150
|
||||
static void readtimezone(void);
|
||||
static int rd_name(char**, char*);
|
||||
static int rd_long(char**, int32_t*);
|
||||
static
|
||||
struct
|
||||
{
|
||||
char stname[4];
|
||||
char dlname[4];
|
||||
int32_t stdiff;
|
||||
int32_t dldiff;
|
||||
int32_t dlpairs[TZSIZE];
|
||||
} timezone;
|
||||
|
||||
char*
|
||||
ctime(int32_t t)
|
||||
{
|
||||
return asctime(localtime(t));
|
||||
}
|
||||
|
||||
Tm*
|
||||
localtime(int32_t tim)
|
||||
{
|
||||
Tm *ct;
|
||||
int32_t t, *p;
|
||||
int dlflag;
|
||||
|
||||
if(timezone.stname[0] == 0)
|
||||
readtimezone();
|
||||
t = tim + timezone.stdiff;
|
||||
dlflag = 0;
|
||||
for(p = timezone.dlpairs; *p; p += 2)
|
||||
if(t >= p[0])
|
||||
if(t < p[1]) {
|
||||
t = tim + timezone.dldiff;
|
||||
dlflag++;
|
||||
break;
|
||||
}
|
||||
ct = gmtime(t);
|
||||
if(dlflag){
|
||||
strcpy(ct->zone, timezone.dlname);
|
||||
ct->tzoff = timezone.dldiff;
|
||||
} else {
|
||||
strcpy(ct->zone, timezone.stname);
|
||||
ct->tzoff = timezone.stdiff;
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
Tm*
|
||||
gmtime(int32_t tim)
|
||||
{
|
||||
int d0, d1;
|
||||
int32_t hms, day;
|
||||
static Tm xtime;
|
||||
|
||||
/*
|
||||
* break initial number into days
|
||||
*/
|
||||
hms = (uint32_t)tim % 86400L;
|
||||
day = (uint32_t)tim / 86400L;
|
||||
if(hms < 0) {
|
||||
hms += 86400L;
|
||||
day -= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate hours:minutes:seconds
|
||||
*/
|
||||
xtime.sec = hms % 60;
|
||||
d1 = hms / 60;
|
||||
xtime.min = d1 % 60;
|
||||
d1 /= 60;
|
||||
xtime.hour = d1;
|
||||
|
||||
/*
|
||||
* day is the day number.
|
||||
* generate day of the week.
|
||||
* The addend is 4 mod 7 (1/1/1970 was Thursday)
|
||||
*/
|
||||
|
||||
xtime.wday = (day + 7340036L) % 7;
|
||||
|
||||
/*
|
||||
* year number
|
||||
*/
|
||||
if(day >= 0)
|
||||
for(d1 = 1970; day >= dysize(d1); d1++)
|
||||
day -= dysize(d1);
|
||||
else
|
||||
for (d1 = 1970; day < 0; d1--)
|
||||
day += dysize(d1-1);
|
||||
xtime.year = d1-1900;
|
||||
xtime.yday = d0 = day;
|
||||
|
||||
/*
|
||||
* generate month
|
||||
*/
|
||||
|
||||
if(dysize(d1) == 366)
|
||||
dmsize[1] = 29;
|
||||
for(d1 = 0; d0 >= dmsize[d1]; d1++)
|
||||
d0 -= dmsize[d1];
|
||||
dmsize[1] = 28;
|
||||
xtime.mday = d0 + 1;
|
||||
xtime.mon = d1;
|
||||
strcpy(xtime.zone, "GMT");
|
||||
return &xtime;
|
||||
}
|
||||
|
||||
char*
|
||||
asctime(Tm *t)
|
||||
{
|
||||
char *ncp;
|
||||
static char cbuf[30];
|
||||
|
||||
strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
|
||||
ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
|
||||
cbuf[0] = *ncp++;
|
||||
cbuf[1] = *ncp++;
|
||||
cbuf[2] = *ncp;
|
||||
ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
|
||||
cbuf[4] = *ncp++;
|
||||
cbuf[5] = *ncp++;
|
||||
cbuf[6] = *ncp;
|
||||
ct_numb(cbuf+8, t->mday);
|
||||
ct_numb(cbuf+11, t->hour+100);
|
||||
ct_numb(cbuf+14, t->min+100);
|
||||
ct_numb(cbuf+17, t->sec+100);
|
||||
ncp = t->zone;
|
||||
cbuf[20] = *ncp++;
|
||||
cbuf[21] = *ncp++;
|
||||
cbuf[22] = *ncp;
|
||||
if(t->year >= 100) {
|
||||
cbuf[24] = '2';
|
||||
cbuf[25] = '0';
|
||||
}
|
||||
ct_numb(cbuf+26, t->year+100);
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
dysize(int y)
|
||||
{
|
||||
|
||||
if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
|
||||
return 366;
|
||||
return 365;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ct_numb(char *cp, int n)
|
||||
{
|
||||
|
||||
cp[0] = ' ';
|
||||
if(n >= 10)
|
||||
cp[0] = (n/10)%10 + '0';
|
||||
cp[1] = n%10 + '0';
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readtimezone(void)
|
||||
{
|
||||
char buf[TZSIZE*11+30], *p;
|
||||
int i;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
i = open("/env/timezone", 0);
|
||||
if(i < 0)
|
||||
goto error;
|
||||
if(read(i, buf, sizeof(buf)) >= sizeof(buf)){
|
||||
close(i);
|
||||
goto error;
|
||||
}
|
||||
close(i);
|
||||
p = buf;
|
||||
if(rd_name(&p, timezone.stname))
|
||||
goto error;
|
||||
if(rd_long(&p, &timezone.stdiff))
|
||||
goto error;
|
||||
if(rd_name(&p, timezone.dlname))
|
||||
goto error;
|
||||
if(rd_long(&p, &timezone.dldiff))
|
||||
goto error;
|
||||
for(i=0; i<TZSIZE; i++) {
|
||||
if(rd_long(&p, &timezone.dlpairs[i]))
|
||||
goto error;
|
||||
if(timezone.dlpairs[i] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
timezone.stdiff = 0;
|
||||
strcpy(timezone.stname, "GMT");
|
||||
timezone.dlpairs[0] = 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
rd_name(char **f, char *p)
|
||||
{
|
||||
int c, i;
|
||||
|
||||
for(;;) {
|
||||
c = *(*f)++;
|
||||
if(c != ' ' && c != '\n')
|
||||
break;
|
||||
}
|
||||
for(i=0; i<3; i++) {
|
||||
if(c == ' ' || c == '\n')
|
||||
return 1;
|
||||
*p++ = c;
|
||||
c = *(*f)++;
|
||||
}
|
||||
if(c != ' ' && c != '\n')
|
||||
return 1;
|
||||
*p = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
rd_long(char **f, int32_t *p)
|
||||
{
|
||||
int c, s;
|
||||
int32_t l;
|
||||
|
||||
s = 0;
|
||||
for(;;) {
|
||||
c = *(*f)++;
|
||||
if(c == '-') {
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
if(c != ' ' && c != '\n')
|
||||
break;
|
||||
}
|
||||
if(c == 0) {
|
||||
*p = 0;
|
||||
return 0;
|
||||
}
|
||||
l = 0;
|
||||
for(;;) {
|
||||
if(c == ' ' || c == '\n')
|
||||
break;
|
||||
if(c < '0' || c > '9')
|
||||
return 1;
|
||||
l = l*10 + c-'0';
|
||||
c = *(*f)++;
|
||||
}
|
||||
if(s)
|
||||
l = -l;
|
||||
*p = l;
|
||||
return 0;
|
||||
}
|
560
sys/src/libc/9sys/dial.c
Normal file
560
sys/src/libc/9sys/dial.c
Normal file
@ -0,0 +1,560 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* dial - connect to a service (parallel version)
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
typedef struct Conn Conn;
|
||||
typedef struct Dest Dest;
|
||||
typedef struct DS DS;
|
||||
|
||||
enum
|
||||
{
|
||||
Maxstring = 128,
|
||||
Maxpath = 256,
|
||||
|
||||
Maxcsreply = 64*80, /* this is probably overly generous */
|
||||
/*
|
||||
* this should be a plausible slight overestimate for non-interactive
|
||||
* use even if it's ridiculously long for interactive use.
|
||||
*/
|
||||
Maxconnms = 2*60*1000, /* 2 minutes */
|
||||
};
|
||||
|
||||
struct DS {
|
||||
/* dist string */
|
||||
char buf[Maxstring];
|
||||
char *netdir;
|
||||
char *proto;
|
||||
char *rem;
|
||||
|
||||
/* other args */
|
||||
const char *local;
|
||||
char *dir;
|
||||
int *cfdp;
|
||||
};
|
||||
|
||||
/*
|
||||
* malloc these; they need to be writable by this proc & all children.
|
||||
* the stack is private to each proc, and static allocation in the data
|
||||
* segment would not permit concurrent dials within a multi-process program.
|
||||
*/
|
||||
struct Conn {
|
||||
int pid;
|
||||
int dead;
|
||||
|
||||
int dfd;
|
||||
int cfd;
|
||||
char dir[NETPATHLEN+1];
|
||||
char err[ERRMAX];
|
||||
};
|
||||
struct Dest {
|
||||
Conn *conn; /* allocated array */
|
||||
Conn *connend;
|
||||
int nkid;
|
||||
|
||||
int32_t oalarm;
|
||||
int naddrs;
|
||||
|
||||
QLock winlck;
|
||||
int winner; /* index into conn[] */
|
||||
|
||||
char *nextaddr;
|
||||
char addrlist[Maxcsreply];
|
||||
};
|
||||
|
||||
static int call(char*, char*, DS*, Dest*, Conn*);
|
||||
static int csdial(DS*);
|
||||
static void _dial_string_parse(const char*, DS*);
|
||||
|
||||
|
||||
/*
|
||||
* the dialstring is of the form '[/net/]proto!dest'
|
||||
*/
|
||||
static int
|
||||
dialimpl(const char *dest, const char *local, char *dir, int *cfdp)
|
||||
{
|
||||
DS ds;
|
||||
int rv;
|
||||
char err[ERRMAX], alterr[ERRMAX];
|
||||
|
||||
ds.local = local;
|
||||
ds.dir = dir;
|
||||
ds.cfdp = cfdp;
|
||||
|
||||
_dial_string_parse(dest, &ds);
|
||||
if(ds.netdir)
|
||||
return csdial(&ds);
|
||||
|
||||
ds.netdir = "/net";
|
||||
rv = csdial(&ds);
|
||||
if(rv >= 0)
|
||||
return rv;
|
||||
err[0] = '\0';
|
||||
errstr(err, sizeof err);
|
||||
if(strstr(err, "refused") != 0){
|
||||
werrstr("%s", err);
|
||||
return rv;
|
||||
}
|
||||
ds.netdir = "/net.alt";
|
||||
rv = csdial(&ds);
|
||||
if(rv >= 0)
|
||||
return rv;
|
||||
|
||||
alterr[0] = 0;
|
||||
errstr(alterr, sizeof alterr);
|
||||
if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
|
||||
werrstr("%s", err);
|
||||
else
|
||||
werrstr("%s", alterr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* the thread library can't cope with rfork(RFMEM|RFPROC),
|
||||
* so it must override this with a private version of dial.
|
||||
*/
|
||||
int (*_dial)(const char *, const char *, char *, int *) = dialimpl;
|
||||
|
||||
int
|
||||
dial(const char *dest, const char *local, char *dir, int *cfdp)
|
||||
{
|
||||
return (*_dial)(dest, local, dir, cfdp);
|
||||
}
|
||||
|
||||
static int
|
||||
connsalloc(Dest *dp, int addrs)
|
||||
{
|
||||
Conn *conn;
|
||||
|
||||
free(dp->conn);
|
||||
dp->connend = nil;
|
||||
assert(addrs > 0);
|
||||
|
||||
dp->conn = mallocz(addrs * sizeof *dp->conn, 1);
|
||||
if(dp->conn == nil)
|
||||
return -1;
|
||||
dp->connend = dp->conn + addrs;
|
||||
for(conn = dp->conn; conn < dp->connend; conn++)
|
||||
conn->cfd = conn->dfd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
freedest(Dest *dp)
|
||||
{
|
||||
int32_t oalarm;
|
||||
|
||||
if (dp == nil)
|
||||
return;
|
||||
oalarm = dp->oalarm;
|
||||
free(dp->conn);
|
||||
free(dp);
|
||||
if (oalarm >= 0)
|
||||
alarm(oalarm);
|
||||
}
|
||||
|
||||
static void
|
||||
closeopenfd(int *fdp)
|
||||
{
|
||||
if (*fdp >= 0) {
|
||||
close(*fdp);
|
||||
*fdp = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
notedeath(Dest *dp, char *exitsts)
|
||||
{
|
||||
int i, n, pid;
|
||||
char *fields[5]; /* pid + 3 times + error */
|
||||
Conn *conn;
|
||||
|
||||
for (i = 0; i < nelem(fields); i++)
|
||||
fields[i] = "";
|
||||
n = tokenize(exitsts, fields, nelem(fields));
|
||||
if (n < 4)
|
||||
return;
|
||||
pid = atoi(fields[0]);
|
||||
if (pid <= 0)
|
||||
return;
|
||||
for (conn = dp->conn; conn < dp->connend; conn++)
|
||||
if (conn->pid == pid && !conn->dead) { /* it's one we know? */
|
||||
if (conn - dp->conn != dp->winner) {
|
||||
closeopenfd(&conn->dfd);
|
||||
closeopenfd(&conn->cfd);
|
||||
}
|
||||
strncpy(conn->err, fields[4], sizeof conn->err - 1);
|
||||
conn->err[sizeof conn->err - 1] = '\0';
|
||||
conn->dead = 1;
|
||||
return;
|
||||
}
|
||||
/* not a proc that we forked */
|
||||
}
|
||||
|
||||
static int
|
||||
outstandingprocs(Dest *dp)
|
||||
{
|
||||
Conn *conn;
|
||||
|
||||
for (conn = dp->conn; conn < dp->connend; conn++)
|
||||
if (!conn->dead)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
reap(Dest *dp)
|
||||
{
|
||||
char exitsts[2*ERRMAX];
|
||||
|
||||
if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) {
|
||||
notedeath(dp, exitsts);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fillinds(DS *ds, Dest *dp)
|
||||
{
|
||||
Conn *conn;
|
||||
|
||||
if (dp->winner < 0)
|
||||
return -1;
|
||||
conn = &dp->conn[dp->winner];
|
||||
if (ds->cfdp)
|
||||
*ds->cfdp = conn->cfd;
|
||||
if (ds->dir) {
|
||||
strncpy(ds->dir, conn->dir, NETPATHLEN);
|
||||
ds->dir[NETPATHLEN-1] = '\0';
|
||||
}
|
||||
return conn->dfd;
|
||||
}
|
||||
|
||||
static int
|
||||
connectwait(Dest *dp, char *besterr)
|
||||
{
|
||||
Conn *conn;
|
||||
|
||||
/* wait for a winner or all attempts to time out */
|
||||
while (dp->winner < 0 && reap(dp) >= 0)
|
||||
;
|
||||
|
||||
/* kill all of our still-live kids & reap them */
|
||||
for (conn = dp->conn; conn < dp->connend; conn++)
|
||||
if (!conn->dead)
|
||||
postnote(PNPROC, conn->pid, "alarm");
|
||||
while (reap(dp) >= 0)
|
||||
;
|
||||
|
||||
/* rummage about and report some error string */
|
||||
for (conn = dp->conn; conn < dp->connend; conn++)
|
||||
if (conn - dp->conn != dp->winner && conn->dead &&
|
||||
conn->err[0]) {
|
||||
strncpy(besterr, conn->err, ERRMAX-1);
|
||||
besterr[ERRMAX-1] = '\0';
|
||||
break;
|
||||
}
|
||||
return dp->winner;
|
||||
}
|
||||
|
||||
static int
|
||||
parsecs(Dest *dp, char **clonep, char **destp)
|
||||
{
|
||||
char *dest, *p;
|
||||
|
||||
dest = strchr(dp->nextaddr, ' ');
|
||||
if(dest == nil) {
|
||||
p = strchr(dp->nextaddr, '\n');
|
||||
if(p)
|
||||
*p = '\0';
|
||||
werrstr("malformed clone cmd from cs `%s'", dp->nextaddr);
|
||||
if(p)
|
||||
*p = '\n';
|
||||
return -1;
|
||||
}
|
||||
*dest++ = '\0';
|
||||
p = strchr(dest, '\n');
|
||||
if(p == nil)
|
||||
return -1;
|
||||
*p++ = '\0';
|
||||
*clonep = dp->nextaddr;
|
||||
*destp = dest;
|
||||
dp->nextaddr = p; /* advance to next line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pickuperr(char *besterr, char *err)
|
||||
{
|
||||
err[0] = '\0';
|
||||
errstr(err, ERRMAX);
|
||||
if(strstr(err, "does not exist") == 0)
|
||||
strcpy(besterr, err);
|
||||
}
|
||||
|
||||
static int
|
||||
catcher(void *v, char *s)
|
||||
{
|
||||
return strstr(s, "alarm") != nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* try all addresses in parallel and take the first one that answers;
|
||||
* this helps when systems have ip v4 and v6 addresses but are
|
||||
* only reachable from here on one (or some) of them.
|
||||
*/
|
||||
static int
|
||||
dialmulti(DS *ds, Dest *dp)
|
||||
{
|
||||
int rv, kid, kidme;
|
||||
char *clone, *dest;
|
||||
char besterr[ERRMAX];
|
||||
|
||||
dp->winner = -1;
|
||||
dp->nkid = 0;
|
||||
while(dp->winner < 0 && *dp->nextaddr != '\0' &&
|
||||
parsecs(dp, &clone, &dest) >= 0) {
|
||||
kidme = dp->nkid++; /* make private copy on stack */
|
||||
kid = rfork(RFPROC|RFMEM); /* spin off a call attempt */
|
||||
if (kid < 0)
|
||||
--dp->nkid;
|
||||
else if (kid == 0) {
|
||||
char err[ERRMAX];
|
||||
|
||||
/* only in kid, to avoid atnotify callbacks in parent */
|
||||
atnotify(catcher, 1);
|
||||
|
||||
*besterr = '\0';
|
||||
rv = call(clone, dest, ds, dp, &dp->conn[kidme]);
|
||||
if(rv < 0)
|
||||
pickuperr(besterr, err);
|
||||
_exits(besterr); /* avoid atexit callbacks */
|
||||
}
|
||||
}
|
||||
*besterr = '\0';
|
||||
rv = connectwait(dp, besterr);
|
||||
if(rv < 0)
|
||||
werrstr("%s", (*besterr? besterr: "unknown error"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
csdial(DS *ds)
|
||||
{
|
||||
int n, fd, rv, addrs, bleft;
|
||||
char c;
|
||||
char *addrp, *clone2, *dest;
|
||||
char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
|
||||
Dest *dp;
|
||||
|
||||
werrstr("");
|
||||
dp = mallocz(sizeof *dp, 1);
|
||||
if(dp == nil)
|
||||
return -1;
|
||||
dp->winner = -1;
|
||||
dp->oalarm = alarm(0);
|
||||
if (connsalloc(dp, 1) < 0) { /* room for a single conn. */
|
||||
freedest(dp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* open connection server
|
||||
*/
|
||||
snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
|
||||
fd = open(buf, ORDWR);
|
||||
if(fd < 0){
|
||||
/* no connection server, don't translate */
|
||||
snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
|
||||
rv = call(clone, ds->rem, ds, dp, &dp->conn[0]);
|
||||
fillinds(ds, dp);
|
||||
freedest(dp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* ask connection server to translate
|
||||
* e.g., net!cs.bell-labs.com!smtp
|
||||
*/
|
||||
snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
|
||||
if(write(fd, buf, strlen(buf)) < 0){
|
||||
close(fd);
|
||||
freedest(dp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* read all addresses from the connection server:
|
||||
* /net/tcp/clone 135.104.9.78!25
|
||||
* /net/tcp/clone 2620:0:dc0:1805::29!25
|
||||
*
|
||||
* assumes that we'll get one record per read.
|
||||
*/
|
||||
seek(fd, 0, 0);
|
||||
addrs = 0;
|
||||
addrp = dp->nextaddr = dp->addrlist;
|
||||
bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */
|
||||
while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) {
|
||||
if (addrp[n-1] != '\n')
|
||||
addrp[n++] = '\n';
|
||||
addrs++;
|
||||
addrp += n;
|
||||
bleft -= n;
|
||||
}
|
||||
*addrp = '\0';
|
||||
|
||||
/*
|
||||
* if we haven't read all of cs's output, assume the last line might
|
||||
* have been truncated and ignore it. we really don't expect this
|
||||
* to happen.
|
||||
*/
|
||||
if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1)
|
||||
addrs--;
|
||||
close(fd);
|
||||
|
||||
*besterr = 0;
|
||||
rv = -1; /* pessimistic default */
|
||||
dp->naddrs = addrs;
|
||||
if (addrs == 0)
|
||||
werrstr("no address to dial");
|
||||
else if (addrs == 1) {
|
||||
/* common case: dial one address without forking */
|
||||
if (parsecs(dp, &clone2, &dest) >= 0 &&
|
||||
(rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) {
|
||||
pickuperr(besterr, err);
|
||||
werrstr("%s", besterr);
|
||||
}
|
||||
} else if (connsalloc(dp, addrs) >= 0)
|
||||
rv = dialmulti(ds, dp);
|
||||
|
||||
/* fill in results */
|
||||
if (rv >= 0 && dp->winner >= 0)
|
||||
rv = fillinds(ds, dp);
|
||||
|
||||
freedest(dp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
|
||||
{
|
||||
int fd, cfd, n, calleralarm, oalarm;
|
||||
char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
|
||||
|
||||
/* because cs is in a different name space, replace the mount point */
|
||||
if(*clone == '/'){
|
||||
p = strchr(clone+1, '/');
|
||||
if(p == nil)
|
||||
p = clone;
|
||||
else
|
||||
p++;
|
||||
} else
|
||||
p = clone;
|
||||
snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
|
||||
|
||||
conn->pid = getpid();
|
||||
conn->cfd = cfd = open(cname, ORDWR);
|
||||
if(cfd < 0)
|
||||
return -1;
|
||||
|
||||
/* get directory name */
|
||||
n = read(cfd, name, sizeof(name)-1);
|
||||
if(n < 0){
|
||||
closeopenfd(&conn->cfd);
|
||||
return -1;
|
||||
}
|
||||
name[n] = 0;
|
||||
for(p = name; *p == ' '; p++)
|
||||
;
|
||||
snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
|
||||
p = strrchr(cname, '/');
|
||||
*p = 0;
|
||||
if(ds->dir)
|
||||
snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name);
|
||||
snprint(data, sizeof(data), "%s/%s/data", cname, name);
|
||||
|
||||
/* should be no alarm pending now; re-instate caller's alarm, if any */
|
||||
calleralarm = dp->oalarm > 0;
|
||||
if (calleralarm)
|
||||
alarm(dp->oalarm);
|
||||
else if (dp->naddrs > 1) /* in a sub-process? */
|
||||
alarm(Maxconnms);
|
||||
|
||||
/* connect */
|
||||
if(ds->local)
|
||||
snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
|
||||
else
|
||||
snprint(name, sizeof(name), "connect %s", dest);
|
||||
if(write(cfd, name, strlen(name)) < 0){
|
||||
closeopenfd(&conn->cfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oalarm = alarm(0); /* don't let alarm interrupt critical section */
|
||||
if (calleralarm)
|
||||
dp->oalarm = oalarm; /* time has passed, so update user's */
|
||||
|
||||
/* open data connection */
|
||||
conn->dfd = fd = open(data, ORDWR);
|
||||
if(fd < 0){
|
||||
closeopenfd(&conn->cfd);
|
||||
alarm(dp->oalarm);
|
||||
return -1;
|
||||
}
|
||||
if(ds->cfdp == nil)
|
||||
closeopenfd(&conn->cfd);
|
||||
|
||||
n = conn - dp->conn;
|
||||
if (dp->winner < 0) {
|
||||
qlock(&dp->winlck);
|
||||
if (dp->winner < 0 && conn < dp->connend)
|
||||
dp->winner = n;
|
||||
qunlock(&dp->winlck);
|
||||
}
|
||||
alarm(calleralarm? dp->oalarm: 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse a dial string
|
||||
*/
|
||||
static void
|
||||
_dial_string_parse(const char *str, DS *ds)
|
||||
{
|
||||
char *p, *p2;
|
||||
|
||||
strncpy(ds->buf, str, Maxstring);
|
||||
ds->buf[Maxstring-1] = 0;
|
||||
|
||||
p = strchr(ds->buf, '!');
|
||||
if(p == 0) {
|
||||
ds->netdir = 0;
|
||||
ds->proto = "net";
|
||||
ds->rem = ds->buf;
|
||||
} else {
|
||||
if(*ds->buf != '/' && *ds->buf != '#'){
|
||||
ds->netdir = 0;
|
||||
ds->proto = ds->buf;
|
||||
} else {
|
||||
/* expecting /net.alt/tcp!foo or #I1/tcp!foo */
|
||||
for(p2 = p; p2 > ds->buf && *p2 != '/'; p2--)
|
||||
;
|
||||
*p2++ = 0;
|
||||
ds->netdir = ds->buf;
|
||||
ds->proto = p2;
|
||||
}
|
||||
*p = 0;
|
||||
ds->rem = p + 1;
|
||||
}
|
||||
}
|
46
sys/src/libc/9sys/dirfstat.c
Normal file
46
sys/src/libc/9sys/dirfstat.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
enum
|
||||
{
|
||||
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
|
||||
};
|
||||
|
||||
Dir*
|
||||
dirfstat(int fd)
|
||||
{
|
||||
Dir *d;
|
||||
uint8_t *buf;
|
||||
int n, nd, i;
|
||||
|
||||
nd = DIRSIZE;
|
||||
for(i=0; i<2; i++){ /* should work by the second try */
|
||||
d = malloc(sizeof(Dir) + BIT16SZ + nd);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
buf = (uint8_t*)&d[1];
|
||||
n = fstat(fd, buf, BIT16SZ+nd);
|
||||
if(n < BIT16SZ){
|
||||
free(d);
|
||||
return nil;
|
||||
}
|
||||
nd = GBIT16(buf); /* upper bound on size of Dir + strings */
|
||||
if(nd <= n){
|
||||
convM2D(buf, n, d, (char*)&d[1]);
|
||||
return d;
|
||||
}
|
||||
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
|
||||
free(d);
|
||||
}
|
||||
return nil;
|
||||
}
|
28
sys/src/libc/9sys/dirfwstat.c
Normal file
28
sys/src/libc/9sys/dirfwstat.c
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
dirfwstat(int fd, Dir *d)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int r;
|
||||
|
||||
r = sizeD2M(d);
|
||||
buf = malloc(r);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
convD2M(d, buf, r);
|
||||
r = fwstat(fd, buf, r);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
57
sys/src/libc/9sys/dirmodefmt.c
Normal file
57
sys/src/libc/9sys/dirmodefmt.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static char *modes[] =
|
||||
{
|
||||
"---",
|
||||
"--x",
|
||||
"-w-",
|
||||
"-wx",
|
||||
"r--",
|
||||
"r-x",
|
||||
"rw-",
|
||||
"rwx",
|
||||
};
|
||||
|
||||
static void
|
||||
rwx(int32_t m, char *s)
|
||||
{
|
||||
strncpy(s, modes[m], 3);
|
||||
}
|
||||
|
||||
int
|
||||
dirmodefmt(Fmt *f)
|
||||
{
|
||||
static char buf[16];
|
||||
uint32_t m;
|
||||
|
||||
m = va_arg(f->args, uint32_t);
|
||||
|
||||
if(m & DMDIR)
|
||||
buf[0]='d';
|
||||
else if(m & DMAPPEND)
|
||||
buf[0]='a';
|
||||
else if(m & DMAUTH)
|
||||
buf[0]='A';
|
||||
else
|
||||
buf[0]='-';
|
||||
if(m & DMEXCL)
|
||||
buf[1]='l';
|
||||
else
|
||||
buf[1]='-';
|
||||
rwx((m>>6)&7, buf+2);
|
||||
rwx((m>>3)&7, buf+5);
|
||||
rwx((m>>0)&7, buf+8);
|
||||
buf[11] = 0;
|
||||
return fmtstrcpy(f, buf);
|
||||
}
|
106
sys/src/libc/9sys/dirread.c
Normal file
106
sys/src/libc/9sys/dirread.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static
|
||||
int32_t
|
||||
dirpackage(uint8_t *buf, int32_t ts, Dir **d)
|
||||
{
|
||||
char *s;
|
||||
int32_t ss, i, n, nn, m;
|
||||
|
||||
*d = nil;
|
||||
if(ts <= 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* first find number of all stats, check they look like stats, & size all associated strings
|
||||
*/
|
||||
ss = 0;
|
||||
n = 0;
|
||||
for(i = 0; i < ts; i += m){
|
||||
m = BIT16SZ + GBIT16(&buf[i]);
|
||||
if(statcheck(&buf[i], m) < 0)
|
||||
break;
|
||||
ss += m;
|
||||
n++;
|
||||
}
|
||||
|
||||
if(i != ts)
|
||||
return -1;
|
||||
|
||||
*d = malloc(n * sizeof(Dir) + ss);
|
||||
if(*d == nil)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* then convert all buffers
|
||||
*/
|
||||
s = (char*)*d + n * sizeof(Dir);
|
||||
nn = 0;
|
||||
for(i = 0; i < ts; i += m){
|
||||
m = BIT16SZ + GBIT16((uint8_t*)&buf[i]);
|
||||
if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
|
||||
free(*d);
|
||||
*d = nil;
|
||||
return -1;
|
||||
}
|
||||
nn++;
|
||||
s += m;
|
||||
}
|
||||
|
||||
return nn;
|
||||
}
|
||||
|
||||
int32_t
|
||||
dirread(int fd, Dir **d)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int32_t ts;
|
||||
|
||||
buf = malloc(DIRMAX);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
ts = read(fd, buf, DIRMAX);
|
||||
if(ts >= 0)
|
||||
ts = dirpackage(buf, ts, d);
|
||||
free(buf);
|
||||
return ts;
|
||||
}
|
||||
|
||||
int32_t
|
||||
dirreadall(int fd, Dir **d)
|
||||
{
|
||||
uint8_t *buf, *nbuf;
|
||||
int32_t n, ts;
|
||||
|
||||
buf = nil;
|
||||
ts = 0;
|
||||
for(;;){
|
||||
nbuf = realloc(buf, ts+DIRMAX);
|
||||
if(nbuf == nil){
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
buf = nbuf;
|
||||
n = read(fd, buf+ts, DIRMAX);
|
||||
if(n <= 0)
|
||||
break;
|
||||
ts += n;
|
||||
}
|
||||
if(ts >= 0)
|
||||
ts = dirpackage(buf, ts, d);
|
||||
free(buf);
|
||||
if(ts == 0 && n < 0)
|
||||
return -1;
|
||||
return ts;
|
||||
}
|
46
sys/src/libc/9sys/dirstat.c
Normal file
46
sys/src/libc/9sys/dirstat.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
enum
|
||||
{
|
||||
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
|
||||
};
|
||||
|
||||
Dir*
|
||||
dirstat(const char *name)
|
||||
{
|
||||
Dir *d;
|
||||
uint8_t *buf;
|
||||
int n, nd, i;
|
||||
|
||||
nd = DIRSIZE;
|
||||
for(i=0; i<2; i++){ /* should work by the second try */
|
||||
d = malloc(sizeof(Dir) + BIT16SZ + nd);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
buf = (uint8_t*)&d[1];
|
||||
n = stat(name, buf, BIT16SZ+nd);
|
||||
if(n < BIT16SZ){
|
||||
free(d);
|
||||
return nil;
|
||||
}
|
||||
nd = GBIT16((uint8_t*)buf); /* upper bound on size of Dir + strings */
|
||||
if(nd <= n){
|
||||
convM2D(buf, n, d, (char*)&d[1]);
|
||||
return d;
|
||||
}
|
||||
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
|
||||
free(d);
|
||||
}
|
||||
return nil;
|
||||
}
|
28
sys/src/libc/9sys/dirwstat.c
Normal file
28
sys/src/libc/9sys/dirwstat.c
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
dirwstat(const char *name, Dir *d)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int r;
|
||||
|
||||
r = sizeD2M(d);
|
||||
buf = malloc(r);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
convD2M(d, buf, r);
|
||||
r = wstat(name, buf, r);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
244
sys/src/libc/9sys/fcallfmt.c
Normal file
244
sys/src/libc/9sys/fcallfmt.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static uint dumpsome(char*, char*, char*, int32_t);
|
||||
static void fdirconv(char*, char*, Dir*);
|
||||
static char *qidtype(char*, uint8_t);
|
||||
|
||||
#define QIDFMT "(%.16llux %lud %s)"
|
||||
|
||||
int
|
||||
fcallfmt(Fmt *fmt)
|
||||
{
|
||||
Fcall *f;
|
||||
int fid, type, tag, i;
|
||||
char buf[512], tmp[200];
|
||||
char *p, *e;
|
||||
Dir *d;
|
||||
Qid *q;
|
||||
|
||||
e = buf+sizeof(buf);
|
||||
f = va_arg(fmt->args, Fcall*);
|
||||
type = f->type;
|
||||
fid = f->fid;
|
||||
tag = f->tag;
|
||||
switch(type){
|
||||
case Tversion: /* 100 */
|
||||
seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
|
||||
break;
|
||||
case Rversion:
|
||||
seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
|
||||
break;
|
||||
case Tauth: /* 102 */
|
||||
seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
|
||||
f->afid, f->uname, f->aname);
|
||||
break;
|
||||
case Rauth:
|
||||
seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
|
||||
f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
|
||||
break;
|
||||
case Tattach: /* 104 */
|
||||
seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
|
||||
fid, f->afid, f->uname, f->aname);
|
||||
break;
|
||||
case Rattach:
|
||||
seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
|
||||
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
|
||||
break;
|
||||
case Rerror: /* 107; 106 (Terror) illegal */
|
||||
seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
|
||||
break;
|
||||
case Tflush: /* 108 */
|
||||
seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
|
||||
break;
|
||||
case Rflush:
|
||||
seprint(buf, e, "Rflush tag %ud", tag);
|
||||
break;
|
||||
case Twalk: /* 110 */
|
||||
p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
|
||||
if(f->nwname <= MAXWELEM)
|
||||
for(i=0; i<f->nwname; i++)
|
||||
p = seprint(p, e, "%d:%s ", i, f->wname[i]);
|
||||
break;
|
||||
case Rwalk:
|
||||
p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
|
||||
if(f->nwqid <= MAXWELEM)
|
||||
for(i=0; i<f->nwqid; i++){
|
||||
q = &f->wqid[i];
|
||||
p = seprint(p, e, "%d:" QIDFMT " ", i,
|
||||
q->path, q->vers, qidtype(tmp, q->type));
|
||||
}
|
||||
break;
|
||||
case Topen: /* 112 */
|
||||
seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
|
||||
break;
|
||||
case Ropen:
|
||||
seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
|
||||
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
|
||||
break;
|
||||
case Tcreate: /* 114 */
|
||||
seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name,
|
||||
(uint32_t)f->perm, f->mode);
|
||||
break;
|
||||
case Rcreate:
|
||||
seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
|
||||
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
|
||||
break;
|
||||
case Tread: /* 116 */
|
||||
seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
|
||||
tag, fid, f->offset, f->count);
|
||||
break;
|
||||
case Rread:
|
||||
p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
|
||||
dumpsome(p, e, f->data, f->count);
|
||||
break;
|
||||
case Twrite: /* 118 */
|
||||
p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
|
||||
tag, fid, f->offset, f->count);
|
||||
dumpsome(p, e, f->data, f->count);
|
||||
break;
|
||||
case Rwrite:
|
||||
seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
|
||||
break;
|
||||
case Tclunk: /* 120 */
|
||||
seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
|
||||
break;
|
||||
case Rclunk:
|
||||
seprint(buf, e, "Rclunk tag %ud", tag);
|
||||
break;
|
||||
case Tremove: /* 122 */
|
||||
seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
|
||||
break;
|
||||
case Rremove:
|
||||
seprint(buf, e, "Rremove tag %ud", tag);
|
||||
break;
|
||||
case Tstat: /* 124 */
|
||||
seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
|
||||
break;
|
||||
case Rstat:
|
||||
p = seprint(buf, e, "Rstat tag %ud ", tag);
|
||||
if(f->nstat > sizeof tmp)
|
||||
seprint(p, e, " stat(%d bytes)", f->nstat);
|
||||
else{
|
||||
d = (Dir*)tmp;
|
||||
convM2D(f->stat, f->nstat, d, (char*)(d+1));
|
||||
seprint(p, e, " stat ");
|
||||
fdirconv(p+6, e, d);
|
||||
}
|
||||
break;
|
||||
case Twstat: /* 126 */
|
||||
p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
|
||||
if(f->nstat > sizeof tmp)
|
||||
seprint(p, e, " stat(%d bytes)", f->nstat);
|
||||
else{
|
||||
d = (Dir*)tmp;
|
||||
convM2D(f->stat, f->nstat, d, (char*)(d+1));
|
||||
seprint(p, e, " stat ");
|
||||
fdirconv(p+6, e, d);
|
||||
}
|
||||
break;
|
||||
case Rwstat:
|
||||
seprint(buf, e, "Rwstat tag %ud", tag);
|
||||
break;
|
||||
default:
|
||||
seprint(buf, e, "unknown type %d", type);
|
||||
}
|
||||
return fmtstrcpy(fmt, buf);
|
||||
}
|
||||
|
||||
static char*
|
||||
qidtype(char *s, uint8_t t)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = s;
|
||||
if(t & QTDIR)
|
||||
*p++ = 'd';
|
||||
if(t & QTAPPEND)
|
||||
*p++ = 'a';
|
||||
if(t & QTEXCL)
|
||||
*p++ = 'l';
|
||||
if(t & QTAUTH)
|
||||
*p++ = 'A';
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
dirfmt(Fmt *fmt)
|
||||
{
|
||||
char buf[160];
|
||||
|
||||
fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
|
||||
return fmtstrcpy(fmt, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
fdirconv(char *buf, char *e, Dir *d)
|
||||
{
|
||||
char tmp[16];
|
||||
|
||||
seprint(buf, e, "'%s' '%s' '%s' '%s' "
|
||||
"q " QIDFMT " m %#luo "
|
||||
"at %ld mt %ld l %lld "
|
||||
"t %d d %d",
|
||||
d->name, d->uid, d->gid, d->muid,
|
||||
d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
|
||||
d->atime, d->mtime, d->length,
|
||||
d->type, d->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* dump out count (or DUMPL, if count is bigger) bytes from
|
||||
* buf to ans, as a string if they are all printable,
|
||||
* else as a series of hex bytes
|
||||
*/
|
||||
#define DUMPL 64
|
||||
|
||||
static uint
|
||||
dumpsome(char *ans, char *e, char *buf, int32_t count)
|
||||
{
|
||||
int i, printable;
|
||||
char *p;
|
||||
|
||||
if(buf == nil){
|
||||
seprint(ans, e, "<no data>");
|
||||
return strlen(ans);
|
||||
}
|
||||
printable = 1;
|
||||
if(count > DUMPL)
|
||||
count = DUMPL;
|
||||
for(i=0; i<count && printable; i++)
|
||||
if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uint8_t)buf[i]>127)
|
||||
printable = 0;
|
||||
p = ans;
|
||||
*p++ = '\'';
|
||||
if(printable){
|
||||
if(count > e-p-2)
|
||||
count = e-p-2;
|
||||
memmove(p, buf, count);
|
||||
p += count;
|
||||
}else{
|
||||
if(2*count > e-p-2)
|
||||
count = (e-p-2)/2;
|
||||
for(i=0; i<count; i++){
|
||||
if(i>0 && i%4==0)
|
||||
*p++ = ' ';
|
||||
sprint(p, "%2.2ux", (uint8_t)buf[i]);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
*p++ = '\'';
|
||||
*p = 0;
|
||||
return p - ans;
|
||||
}
|
17
sys/src/libc/9sys/fork.c
Normal file
17
sys/src/libc/9sys/fork.c
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
fork(void)
|
||||
{
|
||||
return rfork(RFPROC|RFFDG|RFREND);
|
||||
}
|
45
sys/src/libc/9sys/getenv.c
Normal file
45
sys/src/libc/9sys/getenv.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
getenv(const char *name)
|
||||
{
|
||||
int r, f;
|
||||
int32_t s;
|
||||
char *ans;
|
||||
char *p, *ep, ename[100];
|
||||
|
||||
if(strchr(name, '/') != nil)
|
||||
return nil;
|
||||
snprint(ename, sizeof ename, "/env/%s", name);
|
||||
if(strcmp(ename+5, name) != 0)
|
||||
return nil;
|
||||
f = open(ename, OREAD);
|
||||
if(f < 0)
|
||||
return 0;
|
||||
s = seek(f, 0, 2);
|
||||
ans = malloc(s+1);
|
||||
if(ans) {
|
||||
setmalloctag(ans, getcallerpc());
|
||||
seek(f, 0, 0);
|
||||
r = read(f, ans, s);
|
||||
if(r >= 0) {
|
||||
ep = ans + s - 1;
|
||||
for(p = ans; p < ep; p++)
|
||||
if(*p == '\0')
|
||||
*p = ' ';
|
||||
ans[s] = '\0';
|
||||
}
|
||||
}
|
||||
close(f);
|
||||
return ans;
|
||||
}
|
142
sys/src/libc/9sys/getnetconninfo.c
Normal file
142
sys/src/libc/9sys/getnetconninfo.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static char *unknown = "???";
|
||||
|
||||
static void
|
||||
getendpoint(char *dir, char *file, char **sysp, char **servp)
|
||||
{
|
||||
int fd, n;
|
||||
char buf[128];
|
||||
char *sys, *serv;
|
||||
|
||||
sys = serv = 0;
|
||||
|
||||
snprint(buf, sizeof buf, "%s/%s", dir, file);
|
||||
fd = open(buf, OREAD);
|
||||
if(fd >= 0){
|
||||
n = read(fd, buf, sizeof(buf)-1);
|
||||
if(n>0){
|
||||
buf[n-1] = 0;
|
||||
serv = strchr(buf, '!');
|
||||
if(serv){
|
||||
*serv++ = 0;
|
||||
serv = strdup(serv);
|
||||
}
|
||||
sys = strdup(buf);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if(serv == 0)
|
||||
serv = unknown;
|
||||
if(sys == 0)
|
||||
sys = unknown;
|
||||
*servp = serv;
|
||||
*sysp = sys;
|
||||
}
|
||||
|
||||
NetConnInfo*
|
||||
getnetconninfo(const char *dir, int fd)
|
||||
{
|
||||
NetConnInfo *nci;
|
||||
char *cp;
|
||||
Dir *d;
|
||||
char spec[10];
|
||||
char path[128];
|
||||
char netname[128], *p;
|
||||
|
||||
/* get a directory address via fd */
|
||||
if(dir == nil || *dir == 0){
|
||||
if(fd2path(fd, path, sizeof(path)) < 0)
|
||||
return nil;
|
||||
cp = strrchr(path, '/');
|
||||
if(cp == nil)
|
||||
return nil;
|
||||
*cp = 0;
|
||||
dir = path;
|
||||
}
|
||||
|
||||
nci = mallocz(sizeof *nci, 1);
|
||||
if(nci == nil)
|
||||
return nil;
|
||||
|
||||
/* copy connection directory */
|
||||
nci->dir = strdup(dir);
|
||||
if(nci->dir == nil)
|
||||
goto err;
|
||||
|
||||
/* get netroot */
|
||||
nci->root = strdup(dir);
|
||||
if(nci->root == nil)
|
||||
goto err;
|
||||
cp = strchr(nci->root+1, '/');
|
||||
if(cp == nil)
|
||||
goto err;
|
||||
*cp = 0;
|
||||
|
||||
/* figure out bind spec */
|
||||
d = dirstat(nci->dir);
|
||||
if(d != nil){
|
||||
sprint(spec, "#%C%d", d->type, d->dev);
|
||||
nci->spec = strdup(spec);
|
||||
}
|
||||
if(nci->spec == nil)
|
||||
nci->spec = unknown;
|
||||
free(d);
|
||||
|
||||
/* get the two end points */
|
||||
getendpoint(nci->dir, "local", &nci->lsys, &nci->lserv);
|
||||
if(nci->lsys == nil || nci->lserv == nil)
|
||||
goto err;
|
||||
getendpoint(nci->dir, "remote", &nci->rsys, &nci->rserv);
|
||||
if(nci->rsys == nil || nci->rserv == nil)
|
||||
goto err;
|
||||
|
||||
strecpy(netname, netname+sizeof netname, nci->dir);
|
||||
if((p = strrchr(netname, '/')) != nil)
|
||||
*p = 0;
|
||||
if(strncmp(netname, "/net/", 5) == 0)
|
||||
memmove(netname, netname+5, strlen(netname+5)+1);
|
||||
nci->laddr = smprint("%s!%s!%s", netname, nci->lsys, nci->lserv);
|
||||
nci->raddr = smprint("%s!%s!%s", netname, nci->rsys, nci->rserv);
|
||||
if(nci->laddr == nil || nci->raddr == nil)
|
||||
goto err;
|
||||
return nci;
|
||||
err:
|
||||
freenetconninfo(nci);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
xfree(char *x)
|
||||
{
|
||||
if(x == nil || x == unknown)
|
||||
return;
|
||||
free(x);
|
||||
}
|
||||
|
||||
void
|
||||
freenetconninfo(NetConnInfo *nci)
|
||||
{
|
||||
if(nci == nil)
|
||||
return;
|
||||
xfree(nci->root);
|
||||
xfree(nci->dir);
|
||||
xfree(nci->spec);
|
||||
xfree(nci->lsys);
|
||||
xfree(nci->lserv);
|
||||
xfree(nci->rsys);
|
||||
xfree(nci->rserv);
|
||||
xfree(nci->laddr);
|
||||
xfree(nci->raddr);
|
||||
free(nci);
|
||||
}
|
26
sys/src/libc/9sys/getpid.c
Normal file
26
sys/src/libc/9sys/getpid.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
getpid(void)
|
||||
{
|
||||
char b[20];
|
||||
int f;
|
||||
|
||||
memset(b, 0, sizeof(b));
|
||||
f = open("#c/pid", 0);
|
||||
if(f >= 0) {
|
||||
read(f, b, sizeof(b));
|
||||
close(f);
|
||||
}
|
||||
return atol(b);
|
||||
}
|
26
sys/src/libc/9sys/getppid.c
Normal file
26
sys/src/libc/9sys/getppid.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
getppid(void)
|
||||
{
|
||||
char b[20];
|
||||
int f;
|
||||
|
||||
memset(b, 0, sizeof(b));
|
||||
f = open("/dev/ppid", 0);
|
||||
if(f >= 0) {
|
||||
read(f, b, sizeof(b));
|
||||
close(f);
|
||||
}
|
||||
return atol(b);
|
||||
}
|
26
sys/src/libc/9sys/getwd.c
Normal file
26
sys/src/libc/9sys/getwd.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
getwd(char *buf, int nbuf)
|
||||
{
|
||||
int n, fd;
|
||||
|
||||
fd = open(".", OREAD);
|
||||
if(fd < 0)
|
||||
return nil;
|
||||
n = fd2path(fd, buf, nbuf);
|
||||
close(fd);
|
||||
if(n < 0)
|
||||
return nil;
|
||||
return buf;
|
||||
}
|
36
sys/src/libc/9sys/iounit.c
Normal file
36
sys/src/libc/9sys/iounit.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* Format:
|
||||
3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain
|
||||
*/
|
||||
|
||||
int
|
||||
iounit(int fd)
|
||||
{
|
||||
int i, cfd;
|
||||
char buf[128], *args[10];
|
||||
|
||||
snprint(buf, sizeof buf, "#d/%dctl", fd);
|
||||
cfd = open(buf, OREAD);
|
||||
if(cfd < 0)
|
||||
return 0;
|
||||
i = read(cfd, buf, sizeof buf-1);
|
||||
close(cfd);
|
||||
if(i <= 0)
|
||||
return 0;
|
||||
buf[i] = '\0';
|
||||
if(tokenize(buf, args, nelem(args)) != nelem(args))
|
||||
return 0;
|
||||
return atoi(args[7]);
|
||||
}
|
18
sys/src/libc/9sys/nulldir.c
Normal file
18
sys/src/libc/9sys/nulldir.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
nulldir(Dir *d)
|
||||
{
|
||||
memset(d, ~0, sizeof(Dir));
|
||||
d->name = d->uid = d->gid = d->muid = "";
|
||||
}
|
41
sys/src/libc/9sys/postnote.c
Normal file
41
sys/src/libc/9sys/postnote.c
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
postnote(int group, int pid, const char *note)
|
||||
{
|
||||
char file[128];
|
||||
int f, r;
|
||||
|
||||
switch(group) {
|
||||
case PNPROC:
|
||||
sprint(file, "/proc/%d/note", pid);
|
||||
break;
|
||||
case PNGROUP:
|
||||
sprint(file, "/proc/%d/notepg", pid);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
f = open(file, OWRITE);
|
||||
if(f < 0)
|
||||
return -1;
|
||||
|
||||
r = strlen(note);
|
||||
if(write(f, note, r) != r) {
|
||||
close(f);
|
||||
return -1;
|
||||
}
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
54
sys/src/libc/9sys/privalloc.c
Normal file
54
sys/src/libc/9sys/privalloc.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static Lock privlock;
|
||||
static int privinit = 0;
|
||||
static void **privs;
|
||||
|
||||
extern void **_privates;
|
||||
extern int _nprivates;
|
||||
|
||||
void **
|
||||
privalloc(void)
|
||||
{
|
||||
void **p;
|
||||
int i;
|
||||
lock(&privlock);
|
||||
if(!privinit){
|
||||
privinit = 1;
|
||||
if(_nprivates){
|
||||
_privates[0] = 0;
|
||||
for(i = 1; i < _nprivates; i++)
|
||||
_privates[i] = &_privates[i - 1];
|
||||
privs = &_privates[i - 1];
|
||||
}
|
||||
}
|
||||
p = privs;
|
||||
if(p != nil){
|
||||
privs = *p;
|
||||
*p = nil;
|
||||
}
|
||||
unlock(&privlock);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
privfree(void **p)
|
||||
{
|
||||
lock(&privlock);
|
||||
if(p != nil && privinit){
|
||||
*p = privs;
|
||||
privs = p;
|
||||
}
|
||||
unlock(&privlock);
|
||||
}
|
53
sys/src/libc/9sys/pushssl.c
Normal file
53
sys/src/libc/9sys/pushssl.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* Since the SSL device uses decimal file descriptors to name channels,
|
||||
* it is impossible for a user-level file server to stand in for the kernel device.
|
||||
* Thus we hard-code #D rather than use /net/ssl.
|
||||
*/
|
||||
|
||||
int
|
||||
pushssl(int fd, const char *alg, const char *secin, const char *secout, int *cfd)
|
||||
{
|
||||
char buf[8];
|
||||
char dname[64];
|
||||
int n, data, ctl;
|
||||
|
||||
ctl = open("#D/ssl/clone", ORDWR);
|
||||
if(ctl < 0)
|
||||
return -1;
|
||||
n = read(ctl, buf, sizeof(buf)-1);
|
||||
if(n < 0)
|
||||
goto error;
|
||||
buf[n] = 0;
|
||||
sprint(dname, "#D/ssl/%s/data", buf);
|
||||
data = open(dname, ORDWR);
|
||||
if(data < 0)
|
||||
goto error;
|
||||
if(fprint(ctl, "fd %d", fd) < 0 ||
|
||||
fprint(ctl, "secretin %s", secin) < 0 ||
|
||||
fprint(ctl, "secretout %s", secout) < 0 ||
|
||||
fprint(ctl, "alg %s", alg) < 0){
|
||||
close(data);
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
if(cfd != 0)
|
||||
*cfd = ctl;
|
||||
else
|
||||
close(ctl);
|
||||
return data;
|
||||
error:
|
||||
close(ctl);
|
||||
return -1;
|
||||
}
|
35
sys/src/libc/9sys/putenv.c
Normal file
35
sys/src/libc/9sys/putenv.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
putenv(const char *name, const char *val)
|
||||
{
|
||||
int f;
|
||||
char ename[100];
|
||||
int32_t s;
|
||||
|
||||
if(strchr(name, '/') != nil)
|
||||
return -1;
|
||||
snprint(ename, sizeof ename, "/env/%s", name);
|
||||
if(strcmp(ename+5, name) != 0)
|
||||
return -1;
|
||||
f = create(ename, OWRITE, 0664);
|
||||
if(f < 0)
|
||||
return -1;
|
||||
s = strlen(val);
|
||||
if(write(f, val, s) != s){
|
||||
close(f);
|
||||
return -1;
|
||||
}
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
633
sys/src/libc/9sys/qlock.c
Normal file
633
sys/src/libc/9sys/qlock.c
Normal file
@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static struct {
|
||||
QLp *p;
|
||||
QLp x[1024];
|
||||
} ql = {
|
||||
ql.x
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Queuing,
|
||||
QueuingR,
|
||||
QueuingW,
|
||||
Sleeping,
|
||||
};
|
||||
|
||||
static void* (*_rendezvousp)(void*, void*) = rendezvous;
|
||||
|
||||
/* this gets called by the thread library ONLY to get us to use its rendezvous */
|
||||
void
|
||||
_qlockinit(void* (*r)(void*, void*))
|
||||
{
|
||||
_rendezvousp = r;
|
||||
}
|
||||
|
||||
/* find a free shared memory location to queue ourselves in */
|
||||
static QLp*
|
||||
getqlp(void)
|
||||
{
|
||||
QLp *p, *op;
|
||||
|
||||
op = ql.p;
|
||||
for(p = op+1; ; p++){
|
||||
if(p == &ql.x[nelem(ql.x)])
|
||||
p = ql.x;
|
||||
if(p == op)
|
||||
abort();
|
||||
if(_tas(&(p->inuse)) == 0){
|
||||
ql.p = p;
|
||||
p->next = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
static void
|
||||
releaseqlp(QLp **head, QLp **tail, QLp *mp)
|
||||
{
|
||||
/* NOTE: we assume a lock is held during the execution to prevent
|
||||
* modifications to the chain
|
||||
*/
|
||||
QLp *p;
|
||||
|
||||
p = *head;
|
||||
while(p != nil && p != mp && p->next != mp && p != *tail)
|
||||
p = p->next;
|
||||
if(p == nil)
|
||||
abort(); /* mp must be somewhere */
|
||||
|
||||
if(p == mp){
|
||||
/* mp was head */
|
||||
*head = mp->next;
|
||||
} else {
|
||||
p->next = mp->next;
|
||||
}
|
||||
if(*head == nil)
|
||||
*tail = nil;
|
||||
mp->inuse = 0;
|
||||
}
|
||||
|
||||
void
|
||||
qlock(QLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
lock(&q->lock);
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp();
|
||||
p = q->tail;
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->state = Queuing;
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait */
|
||||
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
|
||||
;
|
||||
mp->inuse = 0;
|
||||
}
|
||||
|
||||
void
|
||||
qunlock(QLock *q)
|
||||
{
|
||||
QLp *p;
|
||||
|
||||
lock(&q->lock);
|
||||
if (q->locked == 0)
|
||||
fprint(2, "qunlock called with qlock not held, from %#p\n",
|
||||
getcallerpc());
|
||||
p = q->head;
|
||||
if(p != nil){
|
||||
/* wakeup head waiting process */
|
||||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
unlock(&q->lock);
|
||||
while((*_rendezvousp)(p, (void*)0x12345) == (void*)~0)
|
||||
;
|
||||
return;
|
||||
}
|
||||
q->locked = 0;
|
||||
unlock(&q->lock);
|
||||
}
|
||||
|
||||
int
|
||||
qlockt(QLock *q, uint32_t ms)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
int64_t wkup;
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = awake(ms);
|
||||
|
||||
if(!lockt(&q->lock, ms)){
|
||||
forgivewkp(wkup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!q->locked){
|
||||
forgivewkp(wkup);
|
||||
q->locked = 1;
|
||||
unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp();
|
||||
p = q->tail;
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->state = Queuing;
|
||||
|
||||
if (awakened(wkup)) { /* do not miss already occurred wakeups */
|
||||
releaseqlp(&q->head, &q->tail, mp);
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait */
|
||||
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
|
||||
if (awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
lock(&q->lock);
|
||||
releaseqlp(&q->head, &q->tail, mp);
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
forgivewkp(wkup);
|
||||
mp->inuse = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
canqlock(QLock *q)
|
||||
{
|
||||
if(!canlock(&q->lock))
|
||||
return 0;
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->writer == 0 && q->head == nil){
|
||||
/* no writer, go for it */
|
||||
q->_readers++;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mp = getqlp();
|
||||
p = q->tail;
|
||||
if(p == 0)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingR;
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
|
||||
;
|
||||
mp->inuse = 0;
|
||||
}
|
||||
|
||||
int
|
||||
rlockt(RWLock *q, uint32_t ms)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
int64_t wkup;
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = awake(ms);
|
||||
|
||||
if(!lockt(&q->lock, ms)) {
|
||||
forgivewkp(wkup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(q->writer == 0 && q->head == nil){
|
||||
/* no writer, go for it */
|
||||
forgivewkp(wkup);
|
||||
q->_readers++;
|
||||
unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp();
|
||||
p = q->tail;
|
||||
if(p == 0)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingR;
|
||||
|
||||
if (awakened(wkup)) { /* do not miss already occurred wakeups */
|
||||
releaseqlp(&q->head, &q->tail, mp);
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
|
||||
if (awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
lock(&q->lock);
|
||||
releaseqlp(&q->head, &q->tail, mp);
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
forgivewkp(wkup);
|
||||
mp->inuse = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
canrlock(RWLock *q)
|
||||
{
|
||||
lock(&q->lock);
|
||||
if (q->writer == 0 && q->head == nil) {
|
||||
/* no writer; go for it */
|
||||
q->_readers++;
|
||||
unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
runlock(RWLock *q)
|
||||
{
|
||||
QLp *p;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->_readers <= 0)
|
||||
abort();
|
||||
p = q->head;
|
||||
if(--(q->_readers) > 0 || p == nil){
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start waiting writer */
|
||||
if(p->state != QueuingW)
|
||||
abort();
|
||||
q->head = p->next;
|
||||
if(q->head == 0)
|
||||
q->tail = 0;
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wakeup waiter */
|
||||
while((*_rendezvousp)(p, 0) == (void*)~0)
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
wlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->_readers == 0 && q->writer == 0){
|
||||
/* noone waiting, go for it */
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
p = q->tail;
|
||||
mp = getqlp();
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingW;
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
|
||||
;
|
||||
|
||||
mp->inuse = 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
wlockt(RWLock *q, uint32_t ms)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
int64_t wkup;
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = awake(ms);
|
||||
|
||||
if(!lockt(&q->lock, ms)) {
|
||||
forgivewkp(wkup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(q->_readers == 0 && q->writer == 0){
|
||||
/* noone waiting, go for it */
|
||||
forgivewkp(wkup);
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
p = q->tail;
|
||||
mp = getqlp();
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingW;
|
||||
|
||||
if (awakened(wkup)) { /* do not miss already occurred wakeups */
|
||||
releaseqlp(&q->head, &q->tail, mp);
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
|
||||
if (awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
lock(&q->lock);
|
||||
releaseqlp(&q->head, &q->tail, mp);
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
forgivewkp(wkup);
|
||||
mp->inuse = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
canwlock(RWLock *q)
|
||||
{
|
||||
lock(&q->lock);
|
||||
if (q->_readers == 0 && q->writer == 0) {
|
||||
/* no one waiting; go for it */
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
wunlock(RWLock *q)
|
||||
{
|
||||
QLp *p;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->writer == 0)
|
||||
abort();
|
||||
p = q->head;
|
||||
if(p == nil){
|
||||
q->writer = 0;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
if(p->state == QueuingW){
|
||||
/* start waiting writer */
|
||||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
unlock(&q->lock);
|
||||
while((*_rendezvousp)(p, 0) == (void*)~0)
|
||||
;
|
||||
return;
|
||||
}
|
||||
|
||||
if(p->state != QueuingR)
|
||||
abort();
|
||||
|
||||
/* wake waiting readers */
|
||||
while(q->head != nil && q->head->state == QueuingR){
|
||||
p = q->head;
|
||||
q->head = p->next;
|
||||
q->_readers++;
|
||||
while((*_rendezvousp)(p, 0) == (void*)~0)
|
||||
;
|
||||
}
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
q->writer = 0;
|
||||
unlock(&q->lock);
|
||||
}
|
||||
|
||||
void
|
||||
rsleep(Rendez *r)
|
||||
{
|
||||
QLp *t, *me;
|
||||
|
||||
if(!r->l)
|
||||
abort();
|
||||
lock(&r->l->lock);
|
||||
/* we should hold the qlock */
|
||||
if(!r->l->locked)
|
||||
abort();
|
||||
|
||||
/* add ourselves to the wait list */
|
||||
me = getqlp();
|
||||
me->state = Sleeping;
|
||||
if(r->head == nil)
|
||||
r->head = me;
|
||||
else
|
||||
r->tail->next = me;
|
||||
me->next = nil;
|
||||
r->tail = me;
|
||||
|
||||
/* pass the qlock to the next guy */
|
||||
t = r->l->head;
|
||||
if(t){
|
||||
r->l->head = t->next;
|
||||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
unlock(&r->l->lock);
|
||||
while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
|
||||
;
|
||||
}else{
|
||||
r->l->locked = 0;
|
||||
unlock(&r->l->lock);
|
||||
}
|
||||
|
||||
/* wait for a wakeup */
|
||||
while((*_rendezvousp)(me, (void*)1) == (void*)~0)
|
||||
;
|
||||
me->inuse = 0;
|
||||
}
|
||||
|
||||
int
|
||||
rsleept(Rendez *r, uint32_t ms)
|
||||
{
|
||||
QLp *t, *me;
|
||||
int64_t wkup;
|
||||
|
||||
if(!r->l)
|
||||
abort();
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = awake(ms);
|
||||
|
||||
if(!lockt(&r->l->lock, ms)){
|
||||
forgivewkp(wkup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we should hold the qlock */
|
||||
if(!r->l->locked)
|
||||
abort();
|
||||
|
||||
/* add ourselves to the wait list */
|
||||
me = getqlp();
|
||||
me->state = Sleeping;
|
||||
if(r->head == nil)
|
||||
r->head = me;
|
||||
else
|
||||
r->tail->next = me;
|
||||
me->next = nil;
|
||||
r->tail = me;
|
||||
|
||||
/* pass the qlock to the next guy */
|
||||
t = r->l->head;
|
||||
if(t){
|
||||
r->l->head = t->next;
|
||||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
unlock(&r->l->lock);
|
||||
|
||||
while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
|
||||
;
|
||||
}else{
|
||||
r->l->locked = 0;
|
||||
unlock(&r->l->lock);
|
||||
}
|
||||
|
||||
/* wait for a rwakeup (or a timeout) */
|
||||
do
|
||||
{
|
||||
if (awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
lock(&r->l->lock);
|
||||
releaseqlp(&r->head, &r->tail, me);
|
||||
unlock(&r->l->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
while((*_rendezvousp)(me, (void*)1) == (void*)~0);
|
||||
|
||||
forgivewkp(wkup);
|
||||
me->inuse = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
rwakeup(Rendez *r)
|
||||
{
|
||||
QLp *t;
|
||||
|
||||
/*
|
||||
* take off wait and put on front of queue
|
||||
* put on front so guys that have been waiting will not get starved
|
||||
*/
|
||||
|
||||
if(!r->l)
|
||||
abort();
|
||||
lock(&r->l->lock);
|
||||
if(!r->l->locked)
|
||||
abort();
|
||||
|
||||
t = r->head;
|
||||
if(t == nil){
|
||||
unlock(&r->l->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->head = t->next;
|
||||
if(r->head == nil)
|
||||
r->tail = nil;
|
||||
|
||||
t->next = r->l->head;
|
||||
r->l->head = t;
|
||||
if(r->l->tail == nil)
|
||||
r->l->tail = t;
|
||||
|
||||
t->state = Queuing;
|
||||
unlock(&r->l->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
rwakeupall(Rendez *r)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; rwakeup(r); i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
26
sys/src/libc/9sys/read.c
Normal file
26
sys/src/libc/9sys/read.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* Jehanne is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* Jehanne is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int32_t
|
||||
read(int fd, void* buf, int32_t nbytes)
|
||||
{
|
||||
return pread(fd, buf, nbytes, ~0LL);
|
||||
}
|
40
sys/src/libc/9sys/read9pmsg.c
Normal file
40
sys/src/libc/9sys/read9pmsg.c
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
read9pmsg(int fd, void *abuf, uint n)
|
||||
{
|
||||
int m, len;
|
||||
uint8_t *buf;
|
||||
|
||||
buf = abuf;
|
||||
|
||||
/* read count */
|
||||
m = readn(fd, buf, BIT32SZ);
|
||||
if(m != BIT32SZ){
|
||||
if(m < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = GBIT32(buf);
|
||||
if(len <= BIT32SZ || len > n){
|
||||
werrstr("bad length in 9P2000 message header");
|
||||
return -1;
|
||||
}
|
||||
len -= BIT32SZ;
|
||||
m = readn(fd, buf+BIT32SZ, len);
|
||||
if(m < len)
|
||||
return 0;
|
||||
return BIT32SZ+m;
|
||||
}
|
58
sys/src/libc/9sys/readv.c
Normal file
58
sys/src/libc/9sys/readv.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static
|
||||
int32_t
|
||||
ioreadv(int fd, IOchunk *io, int nio, int64_t offset)
|
||||
{
|
||||
int i;
|
||||
int32_t m, n, tot;
|
||||
char *buf, *p;
|
||||
|
||||
tot = 0;
|
||||
for(i=0; i<nio; i++)
|
||||
tot += io[i].len;
|
||||
buf = malloc(tot);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
|
||||
tot = pread(fd, buf, tot, offset);
|
||||
|
||||
p = buf;
|
||||
n = tot;
|
||||
for(i=0; i<nio; i++){
|
||||
if(n <= 0)
|
||||
break;
|
||||
m = io->len;
|
||||
if(m > n)
|
||||
m = n;
|
||||
memmove(io->addr, p, m);
|
||||
n -= m;
|
||||
p += m;
|
||||
io++;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return tot;
|
||||
}
|
||||
|
||||
int32_t
|
||||
readv(int fd, IOchunk *io, int nio)
|
||||
{
|
||||
return ioreadv(fd, io, nio, -1LL);
|
||||
}
|
||||
|
||||
int32_t
|
||||
preadv(int fd, IOchunk *io, int nio, int64_t off)
|
||||
{
|
||||
return ioreadv(fd, io, nio, off);
|
||||
}
|
22
sys/src/libc/9sys/rerrstr.c
Normal file
22
sys/src/libc/9sys/rerrstr.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
rerrstr(char *buf, uint nbuf)
|
||||
{
|
||||
char tmp[ERRMAX];
|
||||
|
||||
tmp[0] = 0;
|
||||
errstr(tmp, sizeof tmp);
|
||||
utfecpy(buf, buf+nbuf, tmp);
|
||||
errstr(tmp, sizeof tmp);
|
||||
}
|
44
sys/src/libc/9sys/sbrk.c
Normal file
44
sys/src/libc/9sys/sbrk.c
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
extern char end[];
|
||||
static char *bloc = { end };
|
||||
extern int brk_(void*);
|
||||
|
||||
enum
|
||||
{
|
||||
Round = 7
|
||||
};
|
||||
|
||||
int
|
||||
brk(void *p)
|
||||
{
|
||||
uintptr bl;
|
||||
|
||||
bl = ((uintptr)p + Round) & ~Round;
|
||||
if(brk_((void*)bl) < 0)
|
||||
return -1;
|
||||
bloc = (char*)bl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
sbrk(uint32_t n)
|
||||
{
|
||||
uintptr bl;
|
||||
|
||||
bl = ((uintptr)bloc + Round) & ~Round;
|
||||
if(brk_((void*)(bl+n)) < 0)
|
||||
return (void*)-1;
|
||||
bloc = (char*)bl + n;
|
||||
return (void*)bl;
|
||||
}
|
25
sys/src/libc/9sys/setnetmtpt.c
Normal file
25
sys/src/libc/9sys/setnetmtpt.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
setnetmtpt(char *net, int n, const char *x)
|
||||
{
|
||||
if(x == nil)
|
||||
x = "/net";
|
||||
|
||||
if(*x == '/'){
|
||||
strncpy(net, x, n);
|
||||
net[n-1] = 0;
|
||||
} else {
|
||||
snprint(net, n, "/net%s", x);
|
||||
}
|
||||
}
|
31
sys/src/libc/9sys/sleep.c
Normal file
31
sys/src/libc/9sys/sleep.c
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* Jehanne is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* Jehanne is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
sleep(int32_t millisecs)
|
||||
{
|
||||
int64_t wakeup;
|
||||
|
||||
wakeup = awake(millisecs);
|
||||
|
||||
while(!awakened(wakeup) && rendezvous(&wakeup, (void*)1) == (void*)~0)
|
||||
;
|
||||
}
|
37
sys/src/libc/9sys/sysfatal.c
Normal file
37
sys/src/libc/9sys/sysfatal.c
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
|
||||
static void
|
||||
_sysfatalimpl(const char *fmt, va_list arg)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
||||
if(argv0)
|
||||
fprint(2, "%s: %s\n", argv0, buf);
|
||||
else
|
||||
fprint(2, "%s\n", buf);
|
||||
exits(buf);
|
||||
}
|
||||
|
||||
void (*_sysfatal)(const char *fmt, va_list arg) = _sysfatalimpl;
|
||||
|
||||
void
|
||||
sysfatal(const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
(*_sysfatal)(fmt, arg);
|
||||
va_end(arg);
|
||||
}
|
125
sys/src/libc/9sys/syslog.c
Normal file
125
sys/src/libc/9sys/syslog.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static struct
|
||||
{
|
||||
int fd;
|
||||
int consfd;
|
||||
char *name;
|
||||
Dir *d;
|
||||
Dir *consd;
|
||||
Lock;
|
||||
} sl =
|
||||
{
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
static void
|
||||
_syslogopen(void)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
if(sl.fd >= 0)
|
||||
close(sl.fd);
|
||||
snprint(buf, sizeof(buf), "/sys/log/%s", sl.name);
|
||||
sl.fd = open(buf, OWRITE|OCEXEC);
|
||||
}
|
||||
|
||||
static int
|
||||
eqdirdev(Dir *a, Dir *b)
|
||||
{
|
||||
return a != nil && b != nil &&
|
||||
a->dev == b->dev && a->type == b->type &&
|
||||
a->qid.path == b->qid.path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print
|
||||
* sysname: time: mesg
|
||||
* on /sys/log/logname.
|
||||
* If cons or log file can't be opened, print on the system console, too.
|
||||
*/
|
||||
void
|
||||
syslog(int cons, const char *logname, const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
char *ctim, *p;
|
||||
va_list arg;
|
||||
int n;
|
||||
Dir *d;
|
||||
char err[ERRMAX];
|
||||
|
||||
err[0] = '\0';
|
||||
errstr(err, sizeof err);
|
||||
lock(&sl);
|
||||
|
||||
/*
|
||||
* paranoia makes us stat to make sure a fork+close
|
||||
* hasn't broken our fd's
|
||||
*/
|
||||
d = dirfstat(sl.fd);
|
||||
if(sl.fd < 0 || sl.name == nil || strcmp(sl.name, logname) != 0 ||
|
||||
!eqdirdev(d, sl.d)){
|
||||
free(sl.name);
|
||||
sl.name = strdup(logname);
|
||||
if(sl.name == nil)
|
||||
cons = 1;
|
||||
else{
|
||||
free(sl.d);
|
||||
sl.d = nil;
|
||||
_syslogopen();
|
||||
if(sl.fd < 0)
|
||||
cons = 1;
|
||||
else
|
||||
sl.d = dirfstat(sl.fd);
|
||||
}
|
||||
}
|
||||
free(d);
|
||||
if(cons){
|
||||
d = dirfstat(sl.consfd);
|
||||
if(sl.consfd < 0 || !eqdirdev(d, sl.consd)){
|
||||
free(sl.consd);
|
||||
sl.consd = nil;
|
||||
sl.consfd = open("#c/cons", OWRITE|OCEXEC);
|
||||
if(sl.consfd >= 0)
|
||||
sl.consd = dirfstat(sl.consfd);
|
||||
}
|
||||
free(d);
|
||||
}
|
||||
|
||||
if(fmt == nil){
|
||||
unlock(&sl);
|
||||
return;
|
||||
}
|
||||
|
||||
ctim = ctime(time(0));
|
||||
p = buf + snprint(buf, sizeof(buf)-1, "%s ", sysname());
|
||||
strncpy(p, ctim+4, 15);
|
||||
p += 15;
|
||||
*p++ = ' ';
|
||||
errstr(err, sizeof err);
|
||||
va_start(arg, fmt);
|
||||
p = vseprint(p, buf+sizeof(buf)-1, fmt, arg);
|
||||
va_end(arg);
|
||||
*p++ = '\n';
|
||||
n = p - buf;
|
||||
|
||||
if(sl.fd >= 0){
|
||||
seek(sl.fd, 0, 2);
|
||||
write(sl.fd, buf, n);
|
||||
}
|
||||
|
||||
if(cons && sl.consfd >=0)
|
||||
write(sl.consfd, buf, n);
|
||||
|
||||
unlock(&sl);
|
||||
}
|
30
sys/src/libc/9sys/sysname.c
Normal file
30
sys/src/libc/9sys/sysname.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
sysname(void)
|
||||
{
|
||||
int f, n;
|
||||
static char b[128];
|
||||
|
||||
if(b[0])
|
||||
return b;
|
||||
|
||||
f = open("#c/sysname", 0);
|
||||
if(f >= 0) {
|
||||
n = read(f, b, sizeof(b)-1);
|
||||
if(n > 0)
|
||||
b[n] = 0;
|
||||
close(f);
|
||||
}
|
||||
return b;
|
||||
}
|
22
sys/src/libc/9sys/time.c
Normal file
22
sys/src/libc/9sys/time.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int32_t
|
||||
time(int32_t *tp)
|
||||
{
|
||||
int64_t t;
|
||||
|
||||
t = nsec()/1000000000LL;
|
||||
if(tp != nil)
|
||||
*tp = t;
|
||||
return t;
|
||||
}
|
69
sys/src/libc/9sys/times.c
Normal file
69
sys/src/libc/9sys/times.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static
|
||||
char*
|
||||
skip(char *p)
|
||||
{
|
||||
|
||||
while(*p == ' ')
|
||||
p++;
|
||||
while(*p != ' ' && *p != 0)
|
||||
p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* after a fork with fd's copied, both fd's are pointing to
|
||||
* the same Chan structure. Since the offset is kept in the Chan
|
||||
* structure, the seek's and read's in the two processes can be
|
||||
* are competing moving the offset around. Hence the unusual loop
|
||||
* in the middle of this routine.
|
||||
*/
|
||||
int32_t
|
||||
times(int32_t *t)
|
||||
{
|
||||
char b[200], *p;
|
||||
static int f = -1;
|
||||
int i, retries;
|
||||
uint32_t r;
|
||||
|
||||
memset(b, 0, sizeof(b));
|
||||
for(retries = 0; retries < 100; retries++){
|
||||
if(f < 0)
|
||||
f = open("/dev/cputime", OREAD|OCEXEC);
|
||||
if(f < 0)
|
||||
break;
|
||||
if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){
|
||||
close(f);
|
||||
f = -1;
|
||||
} else {
|
||||
if(i != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = b;
|
||||
if(t)
|
||||
t[0] = atol(p);
|
||||
p = skip(p);
|
||||
if(t)
|
||||
t[1] = atol(p);
|
||||
p = skip(p);
|
||||
r = atol(p);
|
||||
if(t){
|
||||
p = skip(p);
|
||||
t[2] = atol(p);
|
||||
p = skip(p);
|
||||
t[3] = atol(p);
|
||||
}
|
||||
return r;
|
||||
}
|
203
sys/src/libc/9sys/tm2sec.c
Normal file
203
sys/src/libc/9sys/tm2sec.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define TZSIZE 150
|
||||
static void readtimezone(void);
|
||||
static int rd_name(char**, char*);
|
||||
static int rd_long(char**, int32_t*);
|
||||
static
|
||||
struct
|
||||
{
|
||||
char stname[4];
|
||||
char dlname[4];
|
||||
int32_t stdiff;
|
||||
int32_t dldiff;
|
||||
int32_t dlpairs[TZSIZE];
|
||||
} timezone;
|
||||
|
||||
#define SEC2MIN 60L
|
||||
#define SEC2HOUR (60L*SEC2MIN)
|
||||
#define SEC2DAY (24L*SEC2HOUR)
|
||||
|
||||
/*
|
||||
* days per month plus days/year
|
||||
*/
|
||||
static int dmsize[] =
|
||||
{
|
||||
365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
static int ldmsize[] =
|
||||
{
|
||||
366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
/*
|
||||
* return the days/month for the given year
|
||||
*/
|
||||
static int *
|
||||
yrsize(int y)
|
||||
{
|
||||
if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
|
||||
return ldmsize;
|
||||
else
|
||||
return dmsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute seconds since Jan 1 1970 GMT
|
||||
* and convert to our timezone.
|
||||
*/
|
||||
int32_t
|
||||
tm2sec(Tm *tm)
|
||||
{
|
||||
int32_t secs;
|
||||
int i, yday, year, *d2m;
|
||||
|
||||
if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0)
|
||||
readtimezone();
|
||||
secs = 0;
|
||||
|
||||
/*
|
||||
* seconds per year
|
||||
*/
|
||||
year = tm->year + 1900;
|
||||
for(i = 1970; i < year; i++){
|
||||
d2m = yrsize(i);
|
||||
secs += d2m[0] * SEC2DAY;
|
||||
}
|
||||
|
||||
/*
|
||||
* if mday is set, use mon and mday to compute yday
|
||||
*/
|
||||
if(tm->mday){
|
||||
yday = 0;
|
||||
d2m = yrsize(year);
|
||||
for(i=0; i<tm->mon; i++)
|
||||
yday += d2m[i+1];
|
||||
yday += tm->mday-1;
|
||||
}else{
|
||||
yday = tm->yday;
|
||||
}
|
||||
secs += yday * SEC2DAY;
|
||||
|
||||
/*
|
||||
* hours, minutes, seconds
|
||||
*/
|
||||
secs += tm->hour * SEC2HOUR;
|
||||
secs += tm->min * SEC2MIN;
|
||||
secs += tm->sec;
|
||||
|
||||
/*
|
||||
* Only handles zones mentioned in /env/timezone,
|
||||
* but things get too ambiguous otherwise.
|
||||
*/
|
||||
if(strcmp(tm->zone, timezone.stname) == 0)
|
||||
secs -= timezone.stdiff;
|
||||
else if(strcmp(tm->zone, timezone.dlname) == 0)
|
||||
secs -= timezone.dldiff;
|
||||
if(secs < 0)
|
||||
secs = 0;
|
||||
return secs;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readtimezone(void)
|
||||
{
|
||||
char buf[TZSIZE*11+30], *p;
|
||||
int i;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
i = open("/env/timezone", 0);
|
||||
if(i < 0)
|
||||
goto error;
|
||||
if(read(i, buf, sizeof(buf)) >= sizeof(buf))
|
||||
goto error;
|
||||
close(i);
|
||||
p = buf;
|
||||
if(rd_name(&p, timezone.stname))
|
||||
goto error;
|
||||
if(rd_long(&p, &timezone.stdiff))
|
||||
goto error;
|
||||
if(rd_name(&p, timezone.dlname))
|
||||
goto error;
|
||||
if(rd_long(&p, &timezone.dldiff))
|
||||
goto error;
|
||||
for(i=0; i<TZSIZE; i++) {
|
||||
if(rd_long(&p, &timezone.dlpairs[i]))
|
||||
goto error;
|
||||
if(timezone.dlpairs[i] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
timezone.stdiff = 0;
|
||||
strcpy(timezone.stname, "GMT");
|
||||
timezone.dlpairs[0] = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rd_name(char **f, char *p)
|
||||
{
|
||||
int c, i;
|
||||
|
||||
for(;;) {
|
||||
c = *(*f)++;
|
||||
if(c != ' ' && c != '\n')
|
||||
break;
|
||||
}
|
||||
for(i=0; i<3; i++) {
|
||||
if(c == ' ' || c == '\n')
|
||||
return 1;
|
||||
*p++ = c;
|
||||
c = *(*f)++;
|
||||
}
|
||||
if(c != ' ' && c != '\n')
|
||||
return 1;
|
||||
*p = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rd_long(char **f, int32_t *p)
|
||||
{
|
||||
int c, s;
|
||||
int32_t l;
|
||||
|
||||
s = 0;
|
||||
for(;;) {
|
||||
c = *(*f)++;
|
||||
if(c == '-') {
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
if(c != ' ' && c != '\n')
|
||||
break;
|
||||
}
|
||||
if(c == 0) {
|
||||
*p = 0;
|
||||
return 0;
|
||||
}
|
||||
l = 0;
|
||||
for(;;) {
|
||||
if(c == ' ' || c == '\n')
|
||||
break;
|
||||
if(c < '0' || c > '9')
|
||||
return 1;
|
||||
l = l*10 + c-'0';
|
||||
c = *(*f)++;
|
||||
}
|
||||
if(s)
|
||||
l = -l;
|
||||
*p = l;
|
||||
return 0;
|
||||
}
|
26
sys/src/libc/9sys/truerand.c
Normal file
26
sys/src/libc/9sys/truerand.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
uint32_t
|
||||
truerand(void)
|
||||
{
|
||||
uint32_t x;
|
||||
static int randfd = -1;
|
||||
|
||||
if(randfd < 0)
|
||||
randfd = open("/dev/random", OREAD|OCEXEC);
|
||||
if(randfd < 0)
|
||||
sysfatal("can't open /dev/random");
|
||||
if(read(randfd, &x, sizeof(x)) != sizeof(x))
|
||||
sysfatal("can't read /dev/random");
|
||||
return x;
|
||||
}
|
41
sys/src/libc/9sys/wait.c
Normal file
41
sys/src/libc/9sys/wait.c
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
Waitmsg*
|
||||
wait(void)
|
||||
{
|
||||
int n, l;
|
||||
char buf[512], *fld[5];
|
||||
Waitmsg *w;
|
||||
|
||||
n = await(buf, sizeof buf-1);
|
||||
if(n < 0)
|
||||
return nil;
|
||||
buf[n] = '\0';
|
||||
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||
werrstr("couldn't parse wait message");
|
||||
return nil;
|
||||
}
|
||||
l = strlen(fld[4])+1;
|
||||
w = malloc(sizeof(Waitmsg)+l);
|
||||
if(w == nil)
|
||||
return nil;
|
||||
w->pid = atoi(fld[0]);
|
||||
w->time[0] = atoi(fld[1]);
|
||||
w->time[1] = atoi(fld[2]);
|
||||
w->time[2] = atoi(fld[3]);
|
||||
w->msg = (char*)&w[1];
|
||||
memmove(w->msg, fld[4], l);
|
||||
return w;
|
||||
}
|
||||
|
30
sys/src/libc/9sys/waitpid.c
Normal file
30
sys/src/libc/9sys/waitpid.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
waitpid(void)
|
||||
{
|
||||
int n;
|
||||
char buf[512], *fld[5];
|
||||
|
||||
n = await(buf, sizeof buf-1);
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
buf[n] = '\0';
|
||||
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||
werrstr("couldn't parse wait message");
|
||||
return -1;
|
||||
}
|
||||
return atoi(fld[0]);
|
||||
}
|
||||
|
23
sys/src/libc/9sys/werrstr.c
Normal file
23
sys/src/libc/9sys/werrstr.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
werrstr(const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char buf[ERRMAX];
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+ERRMAX, fmt, arg);
|
||||
va_end(arg);
|
||||
errstr(buf, ERRMAX);
|
||||
}
|
26
sys/src/libc/9sys/write.c
Normal file
26
sys/src/libc/9sys/write.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* Jehanne is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* Jehanne is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int32_t
|
||||
write(int fd, const void* buf, int32_t nbytes)
|
||||
{
|
||||
return pwrite(fd, buf, nbytes, ~0LL);
|
||||
}
|
51
sys/src/libc/9sys/writev.c
Normal file
51
sys/src/libc/9sys/writev.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static
|
||||
int32_t
|
||||
iowritev(int fd, IOchunk *io, int nio, int64_t offset)
|
||||
{
|
||||
int i;
|
||||
int32_t tot;
|
||||
char *buf, *p;
|
||||
|
||||
tot = 0;
|
||||
for(i=0; i<nio; i++)
|
||||
tot += io[i].len;
|
||||
buf = malloc(tot);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
|
||||
p = buf;
|
||||
for(i=0; i<nio; i++){
|
||||
memmove(p, io->addr, io->len);
|
||||
p += io->len;
|
||||
io++;
|
||||
}
|
||||
|
||||
tot = pwrite(fd, buf, tot, offset);
|
||||
|
||||
free(buf);
|
||||
return tot;
|
||||
}
|
||||
|
||||
int32_t
|
||||
writev(int fd, IOchunk *io, int nio)
|
||||
{
|
||||
return iowritev(fd, io, nio, -1LL);
|
||||
}
|
||||
|
||||
int32_t
|
||||
pwritev(int fd, IOchunk *io, int nio, int64_t off)
|
||||
{
|
||||
return iowritev(fd, io, nio, off);
|
||||
}
|
3
sys/src/libc/9syscall/.gitignore
vendored
Normal file
3
sys/src/libc/9syscall/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/*.s
|
||||
/*.o
|
||||
/sys.h
|
8
sys/src/libc/9syscall/9syscall.json
Normal file
8
sys/src/libc/9syscall/9syscall.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"KernelLibc": {
|
||||
"Pre": [
|
||||
"mksys -o sys.h '-mode=sys.h' $JEHANNE/sys/src/sysconf.json",
|
||||
"mksys -o . '-mode=syscallfiles' $JEHANNE/sys/src/sysconf.json"
|
||||
]
|
||||
}
|
||||
}
|
9
sys/src/libc/amd64/argv0.c
Normal file
9
sys/src/libc/amd64/argv0.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void (*_abort)(void);
|
||||
char *argv0;
|
||||
char *_tos;
|
||||
char *_privates;
|
||||
char *_nprivates;
|
||||
|
86
sys/src/libc/amd64/atom.S
Normal file
86
sys/src/libc/amd64/atom.S
Normal file
@ -0,0 +1,86 @@
|
||||
.text
|
||||
|
||||
.globl ainc /* long ainc(long *); */
|
||||
/* N.B.: long in Plan 9 is 32 BITS! */
|
||||
ainc:
|
||||
|
||||
pushq %rcx
|
||||
ainclp:
|
||||
movl (%rdi), %eax
|
||||
movl %eax, %ecx
|
||||
incl %ecx /* new */
|
||||
lock; cmpxchgl %ecx, (%rdi)
|
||||
jnz ainclp
|
||||
movl %ecx, %eax
|
||||
popq %rcx
|
||||
ret
|
||||
|
||||
.globl adec /* long adec(long*); */
|
||||
adec:
|
||||
pushq %rcx
|
||||
adeclp:
|
||||
movl (%rdi), %eax
|
||||
movl %eax, %ecx
|
||||
decl %ecx /* new */
|
||||
lock; cmpxchgl %ecx, (%rdi)
|
||||
jnz adeclp
|
||||
movl %ecx, %eax
|
||||
popq %rcx
|
||||
ret
|
||||
|
||||
/*
|
||||
* int cas32(u32int *p, u32int ov, u32int nv);
|
||||
* int cas(uint *p, int ov, int nv);
|
||||
* int casul(ulong *p, ulong ov, ulong nv);
|
||||
*/
|
||||
|
||||
.globl cas32
|
||||
cas32:
|
||||
.globl cas
|
||||
cas:
|
||||
.globl casul
|
||||
casul:
|
||||
.globl casl
|
||||
casl:
|
||||
pushq %rcx
|
||||
movl 16(%rdi), %eax
|
||||
movl 24(%rdi), %ebx
|
||||
lock; cmpxchgl %ecx, (%rdi)
|
||||
movl $1, %eax
|
||||
jnz _cas32r0
|
||||
_cas32r1:
|
||||
ret
|
||||
_cas32r0:
|
||||
decl %eax
|
||||
popq %rcx
|
||||
ret
|
||||
|
||||
/*
|
||||
* int cas64(u64int *p, u64int ov, u64int nv);
|
||||
* int casp(void **p, void *ov, void *nv);
|
||||
*/
|
||||
|
||||
.globl cas64
|
||||
cas64:
|
||||
.globl casp
|
||||
casp:
|
||||
pushq %rcx
|
||||
movq 16(%rdi), %rax
|
||||
movq 24(%rdi), %rbx
|
||||
lock; cmpxchgq %rbx, (%rdi)
|
||||
movl $1, %eax
|
||||
jnz _cas64r0
|
||||
_cas64r1:
|
||||
ret
|
||||
_cas64r0:
|
||||
decq %rax
|
||||
popq %rcx
|
||||
ret
|
||||
/*
|
||||
* void mfence(void);
|
||||
*/
|
||||
.globl mfence
|
||||
mfence:
|
||||
mfence
|
||||
ret
|
||||
|
11
sys/src/libc/amd64/cycles.c
Normal file
11
sys/src/libc/amd64/cycles.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void _cycles(uint64_t *x)
|
||||
{
|
||||
uint32_t a, d;
|
||||
|
||||
asm __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
|
||||
|
||||
}
|
||||
|
32
sys/src/libc/amd64/main9.S
Normal file
32
sys/src/libc/amd64/main9.S
Normal file
@ -0,0 +1,32 @@
|
||||
#define NPRIVATES 16
|
||||
|
||||
.text
|
||||
|
||||
// %rdi and %rsi are set up as argc, argv for main.
|
||||
// %rdx points to top of stack
|
||||
.globl _main
|
||||
_main:
|
||||
|
||||
movq 0(%rsp), %rdi
|
||||
leaq 8(%rsp), %rsi
|
||||
movq %rdx, _tos
|
||||
movq $-128, _privates
|
||||
addq %rsp, _privates
|
||||
movl $NPRIVATES, _nprivates
|
||||
leaq -160(%rsp), %rsp
|
||||
call main
|
||||
|
||||
loop:
|
||||
movq $_exits, %rdi
|
||||
call exits
|
||||
jmp loop
|
||||
|
||||
.data
|
||||
_exits:
|
||||
.ascii "main"
|
||||
|
||||
|
||||
.globl gettls0
|
||||
gettls0:
|
||||
movq %fs:0, %rax
|
||||
ret
|
16
sys/src/libc/amd64/notejmp.c
Normal file
16
sys/src/libc/amd64/notejmp.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ureg.h>
|
||||
|
||||
void
|
||||
notejmp(void *vr, jmp_buf j, int ret)
|
||||
{
|
||||
struct Ureg *r = vr;
|
||||
|
||||
r->ax = ret;
|
||||
if(ret == 0)
|
||||
r->ax = 1;
|
||||
r->ip = j[JMPBUFPC];
|
||||
r->sp = j[JMPBUFSP] + 8;
|
||||
noted(NCONT);
|
||||
}
|
9
sys/src/libc/amd64/rdpmc.c
Normal file
9
sys/src/libc/amd64/rdpmc.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
rdpmc (int counter, int low, int high)
|
||||
{
|
||||
asm __volatile__("rdpmc" : "=a" (low), "=d" (high) : "c" (counter)) ;
|
||||
}
|
||||
|
39
sys/src/libc/amd64/setjmp.s
Normal file
39
sys/src/libc/amd64/setjmp.s
Normal file
@ -0,0 +1,39 @@
|
||||
.text
|
||||
|
||||
.globl longjmp
|
||||
longjmp:
|
||||
movq %rdi, %r9
|
||||
movq 0(%r9), %rbx
|
||||
movq 8(%r9), %r12
|
||||
movq 16(%r9), %r13
|
||||
movq 24(%r9), %r14
|
||||
movq 32(%r9), %r15
|
||||
movq 40(%r9), %rbp
|
||||
movq 48(%r9), %rsp
|
||||
movl %esi, %eax
|
||||
test %eax, %eax /* if val != 0 */
|
||||
jnz 1f /* return val */
|
||||
incl %eax /* else return 1 */
|
||||
1:
|
||||
movq 56(%r9), %r8 /* return to caller of setjmp */
|
||||
|
||||
movq 64(%r9), %rdi /* 1st function argument */
|
||||
movq 72(%r9), %rsi /* 2nd function argument */
|
||||
|
||||
jmp *%r8
|
||||
|
||||
.globl setjmp
|
||||
setjmp:
|
||||
movq %rbx, 0(%rdi)
|
||||
movq %r12, 8(%rdi)
|
||||
movq %r13, 16(%rdi)
|
||||
movq %r14, 24(%rdi)
|
||||
movq %r15, 32(%rdi)
|
||||
movq %rbp, 40(%rdi)
|
||||
popq %rdx /* return address */
|
||||
movq %rsp, 48(%rdi)
|
||||
movq %rdx, 56(%rdi)
|
||||
|
||||
|
||||
xorl %eax, %eax /* return 0 */
|
||||
jmp *%rdx
|
5
sys/src/libc/amd64/sqrt.s
Normal file
5
sys/src/libc/amd64/sqrt.s
Normal file
@ -0,0 +1,5 @@
|
||||
.globl sqrt
|
||||
sqrt:
|
||||
sqrtsd %xmm0, %xmm0
|
||||
ret
|
||||
|
10
sys/src/libc/amd64/tas.s
Normal file
10
sys/src/libc/amd64/tas.s
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* The kernel and the libc use the same constant for TAS
|
||||
*/
|
||||
.text
|
||||
.globl _tas
|
||||
_tas:
|
||||
movl $0xdeaddead, %eax
|
||||
xchgl %eax, 0(%rdi) /* lock->key */
|
||||
ret
|
||||
|
255
sys/src/libc/build.json
Normal file
255
sys/src/libc/build.json
Normal file
@ -0,0 +1,255 @@
|
||||
{
|
||||
"Libc": {
|
||||
"Cflags": [
|
||||
"-fasm",
|
||||
"-Werror"
|
||||
],
|
||||
"Include": [
|
||||
"../lib.json"
|
||||
],
|
||||
"Install": "/arch/$ARCH/lib/",
|
||||
"Library": "libc.a",
|
||||
"Post": [
|
||||
"rm 9syscall/*.s"
|
||||
],
|
||||
"Projects": [
|
||||
"9syscall/9syscall.json"
|
||||
],
|
||||
"SourceFiles": [
|
||||
"9sys/access.c",
|
||||
"9sys/announce.c",
|
||||
"9sys/awakened.c",
|
||||
"9sys/convD2M.c",
|
||||
"9sys/convM2D.c",
|
||||
"9sys/convM2S.c",
|
||||
"9sys/convS2M.c",
|
||||
"9sys/cputime.c",
|
||||
"9sys/ctime.c",
|
||||
"9sys/dial.c",
|
||||
"9sys/dirfstat.c",
|
||||
"9sys/dirfwstat.c",
|
||||
"9sys/dirmodefmt.c",
|
||||
"9sys/dirread.c",
|
||||
"9sys/dirstat.c",
|
||||
"9sys/dirwstat.c",
|
||||
"9sys/fcallfmt.c",
|
||||
"9sys/fork.c",
|
||||
"9sys/getnetconninfo.c",
|
||||
"9sys/getenv.c",
|
||||
"9sys/getpid.c",
|
||||
"9sys/getppid.c",
|
||||
"9sys/getwd.c",
|
||||
"9sys/iounit.c",
|
||||
"9sys/nulldir.c",
|
||||
"9sys/postnote.c",
|
||||
"9sys/privalloc.c",
|
||||
"9sys/pushssl.c",
|
||||
"9sys/putenv.c",
|
||||
"9sys/qlock.c",
|
||||
"9sys/read9pmsg.c",
|
||||
"9sys/read.c",
|
||||
"9sys/readv.c",
|
||||
"9sys/rerrstr.c",
|
||||
"9sys/sbrk.c",
|
||||
"9sys/setnetmtpt.c",
|
||||
"9sys/sleep.c",
|
||||
"9sys/sysfatal.c",
|
||||
"9sys/syslog.c",
|
||||
"9sys/sysname.c",
|
||||
"9sys/time.c",
|
||||
"9sys/times.c",
|
||||
"9sys/tm2sec.c",
|
||||
"9sys/truerand.c",
|
||||
"9sys/wait.c",
|
||||
"9sys/waitpid.c",
|
||||
"9sys/werrstr.c",
|
||||
"9sys/write.c",
|
||||
"9sys/writev.c",
|
||||
"9syscall/alarm.s",
|
||||
"9syscall/await.s",
|
||||
"9syscall/awake.s",
|
||||
"9syscall/bind.s",
|
||||
"9syscall/brk_.s",
|
||||
"9syscall/chdir.s",
|
||||
"9syscall/close.s",
|
||||
"9syscall/create.s",
|
||||
"9syscall/dup.s",
|
||||
"9syscall/errstr.s",
|
||||
"9syscall/exec.s",
|
||||
"9syscall/_exits.s",
|
||||
"9syscall/fauth.s",
|
||||
"9syscall/fd2path.s",
|
||||
"9syscall/fstat.s",
|
||||
"9syscall/fversion.s",
|
||||
"9syscall/fwstat.s",
|
||||
"9syscall/mount.s",
|
||||
"9syscall/noted.s",
|
||||
"9syscall/notify.s",
|
||||
"9syscall/nsec.s",
|
||||
"9syscall/open.s",
|
||||
"9syscall/pipe.s",
|
||||
"9syscall/pread.s",
|
||||
"9syscall/pwrite.s",
|
||||
"9syscall/remove.s",
|
||||
"9syscall/rendezvous.s",
|
||||
"9syscall/rfork.s",
|
||||
"9syscall/seek.s",
|
||||
"9syscall/segattach.s",
|
||||
"9syscall/segbrk.s",
|
||||
"9syscall/segdetach.s",
|
||||
"9syscall/segflush.s",
|
||||
"9syscall/segfree.s",
|
||||
"9syscall/semacquire.s",
|
||||
"9syscall/semrelease.s",
|
||||
"9syscall/stat.s",
|
||||
"9syscall/tsemacquire.s",
|
||||
"9syscall/unmount.s",
|
||||
"9syscall/wstat.s",
|
||||
"fmt/dofmt.c",
|
||||
"fmt/dorfmt.c",
|
||||
"fmt/errfmt.c",
|
||||
"fmt/fltfmt.c",
|
||||
"fmt/fmt.c",
|
||||
"fmt/fmtfd.c",
|
||||
"fmt/fmtlock.c",
|
||||
"fmt/fmtprint.c",
|
||||
"fmt/fmtquote.c",
|
||||
"fmt/fmtrune.c",
|
||||
"fmt/fmtstr.c",
|
||||
"fmt/fmtvprint.c",
|
||||
"fmt/fprint.c",
|
||||
"fmt/print.c",
|
||||
"fmt/runefmtstr.c",
|
||||
"fmt/runeseprint.c",
|
||||
"fmt/runesmprint.c",
|
||||
"fmt/runesnprint.c",
|
||||
"fmt/runesprint.c",
|
||||
"fmt/runevseprint.c",
|
||||
"fmt/runevsmprint.c",
|
||||
"fmt/runevsnprint.c",
|
||||
"fmt/seprint.c",
|
||||
"fmt/smprint.c",
|
||||
"fmt/snprint.c",
|
||||
"fmt/sprint.c",
|
||||
"fmt/vfprint.c",
|
||||
"fmt/vseprint.c",
|
||||
"fmt/vsmprint.c",
|
||||
"fmt/vsnprint.c",
|
||||
"port/_assert.c",
|
||||
"port/abs.c",
|
||||
"port/asin.c",
|
||||
"port/atan.c",
|
||||
"port/atan2.c",
|
||||
"port/atexit.c",
|
||||
"port/atnotify.c",
|
||||
"port/atof.c",
|
||||
"port/atol.c",
|
||||
"port/atoll.c",
|
||||
"port/cistrcmp.c",
|
||||
"port/cistrncmp.c",
|
||||
"port/cistrstr.c",
|
||||
"port/charstod.c",
|
||||
"port/cleanname.c",
|
||||
"port/ctype.c",
|
||||
"port/encodefmt.c",
|
||||
"port/execl.c",
|
||||
"port/exp.c",
|
||||
"port/fabs.c",
|
||||
"port/floor.c",
|
||||
"port/fmod.c",
|
||||
"port/frand.c",
|
||||
"port/frexp.c",
|
||||
"port/getcallerpc.c",
|
||||
"port/getfields.c",
|
||||
"port/getuser.c",
|
||||
"port/hangup.c",
|
||||
"port/hypot.c",
|
||||
"port/lnrand.c",
|
||||
"port/lock.c",
|
||||
"port/log.c",
|
||||
"port/lrand.c",
|
||||
"port/malloc.c",
|
||||
"port/memccpy.c",
|
||||
"port/memchr.c",
|
||||
"port/memcmp.c",
|
||||
"port/memmove.c",
|
||||
"port/memset.c",
|
||||
"port/mktemp.c",
|
||||
"port/muldiv.c",
|
||||
"port/nan.c",
|
||||
"port/needsrcquote.c",
|
||||
"port/netmkaddr.c",
|
||||
"port/nrand.c",
|
||||
"port/ntruerand.c",
|
||||
"port/perror.c",
|
||||
"port/pool.c",
|
||||
"port/pow.c",
|
||||
"port/pow10.c",
|
||||
"port/qsort.c",
|
||||
"port/quote.c",
|
||||
"port/rand.c",
|
||||
"port/readn.c",
|
||||
"port/rune.c",
|
||||
"port/runebase.c",
|
||||
"port/runebsearch.c",
|
||||
"port/runestrcat.c",
|
||||
"port/runestrchr.c",
|
||||
"port/runestrcmp.c",
|
||||
"port/runestrcpy.c",
|
||||
"port/runestrecpy.c",
|
||||
"port/runestrdup.c",
|
||||
"port/runestrncat.c",
|
||||
"port/runestrncmp.c",
|
||||
"port/runestrncpy.c",
|
||||
"port/runestrrchr.c",
|
||||
"port/runestrlen.c",
|
||||
"port/runestrstr.c",
|
||||
"port/runetype.c",
|
||||
"port/sin.c",
|
||||
"port/sinh.c",
|
||||
"port/strcat.c",
|
||||
"port/strchr.c",
|
||||
"port/strcmp.c",
|
||||
"port/strcpy.c",
|
||||
"port/strecpy.c",
|
||||
"port/strcspn.c",
|
||||
"port/strdup.c",
|
||||
"port/strlen.c",
|
||||
"port/strncat.c",
|
||||
"port/strncmp.c",
|
||||
"port/strncpy.c",
|
||||
"port/strpbrk.c",
|
||||
"port/strrchr.c",
|
||||
"port/strspn.c",
|
||||
"port/strstr.c",
|
||||
"port/strtod.c",
|
||||
"port/strtok.c",
|
||||
"port/strtol.c",
|
||||
"port/strtoll.c",
|
||||
"port/strtoul.c",
|
||||
"port/strtoull.c",
|
||||
"port/tan.c",
|
||||
"port/tanh.c",
|
||||
"port/tokenize.c",
|
||||
"port/toupper.c",
|
||||
"port/utfecpy.c",
|
||||
"port/utflen.c",
|
||||
"port/utfnlen.c",
|
||||
"port/utfrune.c",
|
||||
"port/utfrrune.c",
|
||||
"port/utfutf.c",
|
||||
"port/u16.c",
|
||||
"port/u32.c",
|
||||
"port/u64.c",
|
||||
"$ARCH/notejmp.c",
|
||||
"$ARCH/cycles.c",
|
||||
"$ARCH/argv0.c",
|
||||
"$ARCH/rdpmc.c",
|
||||
"$ARCH/setjmp.s",
|
||||
"$ARCH/sqrt.s",
|
||||
"$ARCH/tas.s",
|
||||
"$ARCH/atom.S",
|
||||
"$ARCH/main9.S"
|
||||
]
|
||||
}
|
||||
}
|
539
sys/src/libc/fmt/dofmt.c
Normal file
539
sys/src/libc/fmt/dofmt.c
Normal file
@ -0,0 +1,539 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/* format the output into f->to and return the number of characters fmted */
|
||||
int
|
||||
dofmt(Fmt *f, const char *fmt)
|
||||
{
|
||||
Rune rune, *rt, *rs;
|
||||
int r;
|
||||
char *t, *s;
|
||||
int n, nfmt;
|
||||
|
||||
nfmt = f->nfmt;
|
||||
for(;;){
|
||||
if(f->runes){
|
||||
rt = f->to;
|
||||
rs = f->stop;
|
||||
while((r = *(uint8_t*)fmt) && r != '%'){
|
||||
if(r < Runeself)
|
||||
fmt++;
|
||||
else{
|
||||
fmt += chartorune(&rune, fmt);
|
||||
r = rune;
|
||||
}
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
}
|
||||
fmt++;
|
||||
f->nfmt += rt - (Rune *)f->to;
|
||||
f->to = rt;
|
||||
if(!r)
|
||||
return f->nfmt - nfmt;
|
||||
f->stop = rs;
|
||||
}else{
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
while((r = *(uint8_t*)fmt) && r != '%'){
|
||||
if(r < Runeself){
|
||||
FMTCHAR(f, t, s, r);
|
||||
fmt++;
|
||||
}else{
|
||||
n = chartorune(&rune, fmt);
|
||||
if(t + n > s){
|
||||
t = _fmtflush(f, t, n);
|
||||
if(t != nil)
|
||||
s = f->stop;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
while(n--)
|
||||
*t++ = *fmt++;
|
||||
}
|
||||
}
|
||||
fmt++;
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(!r)
|
||||
return f->nfmt - nfmt;
|
||||
f->stop = s;
|
||||
}
|
||||
|
||||
fmt = _fmtdispatch(f, fmt, 0);
|
||||
if(fmt == nil)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
_fmtflush(Fmt *f, void *t, int len)
|
||||
{
|
||||
if(f->runes)
|
||||
f->nfmt += (Rune*)t - (Rune*)f->to;
|
||||
else
|
||||
f->nfmt += (char*)t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
|
||||
f->stop = f->to;
|
||||
return nil;
|
||||
}
|
||||
return f->to;
|
||||
}
|
||||
|
||||
/*
|
||||
* put a formatted block of memory sz bytes long of n runes into the output buffer,
|
||||
* left/right justified in a field of at least f->width charactes
|
||||
*/
|
||||
int
|
||||
_fmtpad(Fmt *f, int n)
|
||||
{
|
||||
char *t, *s;
|
||||
int i;
|
||||
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
for(i = 0; i < n; i++)
|
||||
FMTCHAR(f, t, s, ' ');
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rfmtpad(Fmt *f, int n)
|
||||
{
|
||||
Rune *t, *s;
|
||||
int i;
|
||||
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
for(i = 0; i < n; i++)
|
||||
FMTRCHAR(f, t, s, ' ');
|
||||
f->nfmt += t - (Rune *)f->to;
|
||||
f->to = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_fmtcpy(Fmt *f, const void *vm, int n, int sz)
|
||||
{
|
||||
Rune *rt, *rs, r;
|
||||
char *t, *s;
|
||||
const char *m, *me;
|
||||
uint32_t fl;
|
||||
int nc, w;
|
||||
|
||||
m = vm;
|
||||
me = m + sz;
|
||||
w = f->width;
|
||||
fl = f->flags;
|
||||
if((fl & FmtPrec) && n > f->prec)
|
||||
n = f->prec;
|
||||
if(f->runes){
|
||||
if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
rt = f->to;
|
||||
rs = f->stop;
|
||||
for(nc = n; nc > 0; nc--){
|
||||
r = *(uint8_t*)m;
|
||||
if(r < Runeself)
|
||||
m++;
|
||||
else if((me - m) >= UTFmax || fullrune(m, me-m))
|
||||
m += chartorune(&r, m);
|
||||
else
|
||||
break;
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
}
|
||||
f->nfmt += rt - (Rune *)f->to;
|
||||
f->to = rt;
|
||||
if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
}else{
|
||||
if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
for(nc = n; nc > 0; nc--){
|
||||
r = *(uint8_t*)m;
|
||||
if(r < Runeself)
|
||||
m++;
|
||||
else if((me - m) >= UTFmax || fullrune(m, me-m))
|
||||
m += chartorune(&r, m);
|
||||
else
|
||||
break;
|
||||
FMTRUNE(f, t, s, r);
|
||||
}
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_fmtrcpy(Fmt *f, const void *vm, int n)
|
||||
{
|
||||
Rune r, *rt, *rs;
|
||||
const Rune *m, *me;
|
||||
char *t, *s;
|
||||
uint32_t fl;
|
||||
int w;
|
||||
|
||||
m = vm;
|
||||
w = f->width;
|
||||
fl = f->flags;
|
||||
if((fl & FmtPrec) && n > f->prec)
|
||||
n = f->prec;
|
||||
if(f->runes){
|
||||
if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
rt = f->to;
|
||||
rs = f->stop;
|
||||
for(me = m + n; m < me; m++)
|
||||
FMTRCHAR(f, rt, rs, *m);
|
||||
f->nfmt += rt - (Rune *)f->to;
|
||||
f->to = rt;
|
||||
if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
}else{
|
||||
if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
for(me = m + n; m < me; m++){
|
||||
r = *m;
|
||||
FMTRUNE(f, t, s, r);
|
||||
}
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fmt out one character */
|
||||
int
|
||||
_charfmt(Fmt *f)
|
||||
{
|
||||
char x[1];
|
||||
|
||||
x[0] = va_arg(f->args, int);
|
||||
f->prec = 1;
|
||||
return _fmtcpy(f, x, 1, 1);
|
||||
}
|
||||
|
||||
/* fmt out one rune */
|
||||
int
|
||||
_runefmt(Fmt *f)
|
||||
{
|
||||
Rune x[1];
|
||||
|
||||
x[0] = va_arg(f->args, int);
|
||||
return _fmtrcpy(f, x, 1);
|
||||
}
|
||||
|
||||
/* public helper routine: fmt out a null terminated string already in hand */
|
||||
int
|
||||
fmtstrcpy(Fmt *f, const char *s)
|
||||
{
|
||||
int i, j;
|
||||
Rune r;
|
||||
|
||||
if(!s)
|
||||
return _fmtcpy(f, "<nil>", 5, 5);
|
||||
/* if precision is specified, make sure we don't wander off the end */
|
||||
if(f->flags & FmtPrec){
|
||||
i = 0;
|
||||
for(j=0; j<f->prec && s[i]; j++)
|
||||
i += chartorune(&r, s+i);
|
||||
return _fmtcpy(f, s, j, i);
|
||||
}
|
||||
return _fmtcpy(f, s, utflen(s), strlen(s));
|
||||
}
|
||||
|
||||
/* fmt out a null terminated utf string */
|
||||
int
|
||||
_strfmt(Fmt *f)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = va_arg(f->args, char *);
|
||||
return fmtstrcpy(f, s);
|
||||
}
|
||||
|
||||
/* public helper routine: fmt out a null terminated rune string already in hand */
|
||||
int
|
||||
fmtrunestrcpy(Fmt *f, const Rune *s)
|
||||
{
|
||||
const Rune *e;
|
||||
int n, p;
|
||||
|
||||
if(!s)
|
||||
return _fmtcpy(f, "<nil>", 5, 5);
|
||||
/* if precision is specified, make sure we don't wander off the end */
|
||||
if(f->flags & FmtPrec){
|
||||
p = f->prec;
|
||||
for(n = 0; n < p; n++)
|
||||
if(s[n] == 0)
|
||||
break;
|
||||
}else{
|
||||
for(e = s; *e; e++)
|
||||
;
|
||||
n = e - s;
|
||||
}
|
||||
return _fmtrcpy(f, s, n);
|
||||
}
|
||||
|
||||
/* fmt out a null terminated rune string */
|
||||
int
|
||||
_runesfmt(Fmt *f)
|
||||
{
|
||||
Rune *s;
|
||||
|
||||
s = va_arg(f->args, Rune *);
|
||||
return fmtrunestrcpy(f, s);
|
||||
}
|
||||
|
||||
/* fmt a % */
|
||||
int
|
||||
_percentfmt(Fmt *f)
|
||||
{
|
||||
Rune x[1];
|
||||
|
||||
x[0] = f->r;
|
||||
f->prec = 1;
|
||||
return _fmtrcpy(f, x, 1);
|
||||
}
|
||||
|
||||
enum {
|
||||
/* %,#llb could emit a sign, "0b" and 64 digits with 21 commas */
|
||||
Maxintwidth = 1 + 2 + 64 + 64/3,
|
||||
};
|
||||
|
||||
/* fmt an integer */
|
||||
int
|
||||
_ifmt(Fmt *f)
|
||||
{
|
||||
char buf[Maxintwidth + 1], *p, *conv;
|
||||
uint64_t vu;
|
||||
uint32_t u;
|
||||
uintptr pu;
|
||||
int neg, base, i, n, fl, w, isv;
|
||||
|
||||
neg = 0;
|
||||
fl = f->flags;
|
||||
isv = 0;
|
||||
vu = 0;
|
||||
u = 0;
|
||||
if(f->r == 'p'){
|
||||
pu = va_arg(f->args, uintptr);
|
||||
if(sizeof(uintptr) == sizeof(uint64_t)){
|
||||
vu = pu;
|
||||
isv = 1;
|
||||
}else
|
||||
u = pu;
|
||||
f->r = 'x';
|
||||
fl |= FmtUnsigned;
|
||||
}else if(fl & FmtVLong){
|
||||
isv = 1;
|
||||
if(fl & FmtUnsigned)
|
||||
vu = va_arg(f->args, uint64_t);
|
||||
else
|
||||
vu = va_arg(f->args, int64_t);
|
||||
}else if(fl & FmtLong){
|
||||
if(fl & FmtUnsigned)
|
||||
u = va_arg(f->args, uint32_t);
|
||||
else
|
||||
u = va_arg(f->args, int32_t);
|
||||
}else if(fl & FmtByte){
|
||||
if(fl & FmtUnsigned)
|
||||
u = (uint8_t)va_arg(f->args, int);
|
||||
else
|
||||
u = (char)va_arg(f->args, int);
|
||||
}else if(fl & FmtShort){
|
||||
if(fl & FmtUnsigned)
|
||||
u = (uint16_t)va_arg(f->args, int);
|
||||
else
|
||||
u = (int16_t)va_arg(f->args, int);
|
||||
}else{
|
||||
if(fl & FmtUnsigned)
|
||||
u = va_arg(f->args, uint);
|
||||
else
|
||||
u = va_arg(f->args, int);
|
||||
}
|
||||
conv = "0123456789abcdef";
|
||||
switch(f->r){
|
||||
case 'd':
|
||||
base = 10;
|
||||
break;
|
||||
case 'x':
|
||||
base = 16;
|
||||
break;
|
||||
case 'X':
|
||||
base = 16;
|
||||
conv = "0123456789ABCDEF";
|
||||
break;
|
||||
case 'b':
|
||||
base = 2;
|
||||
break;
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if(!(fl & FmtUnsigned)){
|
||||
if(isv && (int64_t)vu < 0){
|
||||
vu = -(int64_t)vu;
|
||||
neg = 1;
|
||||
}else if(!isv && (int32_t)u < 0){
|
||||
u = -(int32_t)u;
|
||||
neg = 1;
|
||||
}
|
||||
}
|
||||
p = buf + sizeof buf - 1;
|
||||
n = 0;
|
||||
if(isv){
|
||||
while(vu){
|
||||
i = vu % base;
|
||||
vu /= base;
|
||||
if((fl & FmtComma) && n % 4 == 3){
|
||||
*p-- = ',';
|
||||
n++;
|
||||
}
|
||||
*p-- = conv[i];
|
||||
n++;
|
||||
}
|
||||
}else{
|
||||
while(u){
|
||||
i = u % base;
|
||||
u /= base;
|
||||
if((fl & FmtComma) && n % 4 == 3){
|
||||
*p-- = ',';
|
||||
n++;
|
||||
}
|
||||
*p-- = conv[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if(n == 0){
|
||||
*p-- = '0';
|
||||
n = 1;
|
||||
}
|
||||
for(w = f->prec; n < w && p > buf+3; n++)
|
||||
*p-- = '0';
|
||||
if(neg || (fl & (FmtSign|FmtSpace)))
|
||||
n++;
|
||||
if(fl & FmtSharp){
|
||||
if(base == 16)
|
||||
n += 2;
|
||||
else if(base == 8){
|
||||
if(p[1] == '0')
|
||||
fl &= ~FmtSharp;
|
||||
else
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
|
||||
for(w = f->width; n < w && p > buf+3; n++)
|
||||
*p-- = '0';
|
||||
f->width = 0;
|
||||
}
|
||||
if(fl & FmtSharp){
|
||||
if(base == 16)
|
||||
*p-- = f->r;
|
||||
if(base == 16 || base == 8)
|
||||
*p-- = '0';
|
||||
}
|
||||
if(neg)
|
||||
*p-- = '-';
|
||||
else if(fl & FmtSign)
|
||||
*p-- = '+';
|
||||
else if(fl & FmtSpace)
|
||||
*p-- = ' ';
|
||||
f->flags &= ~FmtPrec;
|
||||
return _fmtcpy(f, p + 1, n, n);
|
||||
}
|
||||
|
||||
int
|
||||
_countfmt(Fmt *f)
|
||||
{
|
||||
void *p;
|
||||
uint32_t fl;
|
||||
|
||||
fl = f->flags;
|
||||
p = va_arg(f->args, void*);
|
||||
if(fl & FmtVLong){
|
||||
*(int64_t*)p = f->nfmt;
|
||||
}else if(fl & FmtLong){
|
||||
*(int32_t*)p = f->nfmt;
|
||||
}else if(fl & FmtByte){
|
||||
*(char*)p = f->nfmt;
|
||||
}else if(fl & FmtShort){
|
||||
*(int16_t*)p = f->nfmt;
|
||||
}else{
|
||||
*(int*)p = f->nfmt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_flagfmt(Fmt *f)
|
||||
{
|
||||
switch(f->r){
|
||||
case ',':
|
||||
f->flags |= FmtComma;
|
||||
break;
|
||||
case '-':
|
||||
f->flags |= FmtLeft;
|
||||
break;
|
||||
case '+':
|
||||
f->flags |= FmtSign;
|
||||
break;
|
||||
case '#':
|
||||
f->flags |= FmtSharp;
|
||||
break;
|
||||
case ' ':
|
||||
f->flags |= FmtSpace;
|
||||
break;
|
||||
case 'u':
|
||||
f->flags |= FmtUnsigned;
|
||||
break;
|
||||
case 'h':
|
||||
if(f->flags & FmtShort)
|
||||
f->flags |= FmtByte;
|
||||
f->flags |= FmtShort;
|
||||
break;
|
||||
case 'l':
|
||||
if(f->flags & FmtLong)
|
||||
f->flags |= FmtVLong;
|
||||
f->flags |= FmtLong;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* default error format */
|
||||
int
|
||||
_badfmt(Fmt *f)
|
||||
{
|
||||
Rune x[3];
|
||||
|
||||
x[0] = '%';
|
||||
x[1] = f->r;
|
||||
x[2] = '%';
|
||||
f->prec = 3;
|
||||
_fmtrcpy(f, x, 3);
|
||||
return 0;
|
||||
}
|
54
sys/src/libc/fmt/dorfmt.c
Normal file
54
sys/src/libc/fmt/dorfmt.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/* format the output into f->to and return the number of characters fmted */
|
||||
|
||||
int
|
||||
dorfmt(Fmt *f, const Rune *fmt)
|
||||
{
|
||||
Rune *rt, *rs;
|
||||
int r;
|
||||
char *t, *s;
|
||||
int nfmt;
|
||||
|
||||
nfmt = f->nfmt;
|
||||
for(;;){
|
||||
if(f->runes){
|
||||
rt = f->to;
|
||||
rs = f->stop;
|
||||
while((r = *fmt++) && r != '%'){
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
}
|
||||
f->nfmt += rt - (Rune *)f->to;
|
||||
f->to = rt;
|
||||
if(!r)
|
||||
return f->nfmt - nfmt;
|
||||
f->stop = rs;
|
||||
}else{
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
while((r = *fmt++) && r != '%'){
|
||||
FMTRUNE(f, t, f->stop, r);
|
||||
}
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(!r)
|
||||
return f->nfmt - nfmt;
|
||||
f->stop = s;
|
||||
}
|
||||
|
||||
fmt = _fmtdispatch(f, fmt, 1);
|
||||
if(fmt == nil)
|
||||
return -1;
|
||||
}
|
||||
}
|
21
sys/src/libc/fmt/errfmt.c
Normal file
21
sys/src/libc/fmt/errfmt.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
int
|
||||
errfmt(Fmt *f)
|
||||
{
|
||||
char buf[ERRMAX];
|
||||
|
||||
rerrstr(buf, sizeof buf);
|
||||
return _fmtcpy(f, buf, utflen(buf), strlen(buf));
|
||||
}
|
327
sys/src/libc/fmt/fltfmt.c
Normal file
327
sys/src/libc/fmt/fltfmt.c
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
enum
|
||||
{
|
||||
FDIGIT = 30,
|
||||
FDEFLT = 6,
|
||||
NSIGNIF = 17,
|
||||
NEXP10 = 308,
|
||||
};
|
||||
|
||||
static int
|
||||
xadd(char *a, int n, int v)
|
||||
{
|
||||
char *b;
|
||||
int c;
|
||||
|
||||
if(n < 0 || n >= NSIGNIF)
|
||||
return 0;
|
||||
for(b = a+n; b >= a; b--) {
|
||||
c = *b + v;
|
||||
if(c <= '9') {
|
||||
*b = c;
|
||||
return 0;
|
||||
}
|
||||
*b = '0';
|
||||
v = 1;
|
||||
}
|
||||
*a = '1'; // overflow adding
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
xsub(char *a, int n, int v)
|
||||
{
|
||||
char *b;
|
||||
int c;
|
||||
|
||||
for(b = a+n; b >= a; b--) {
|
||||
c = *b - v;
|
||||
if(c >= '0') {
|
||||
*b = c;
|
||||
return 0;
|
||||
}
|
||||
*b = '9';
|
||||
v = 1;
|
||||
}
|
||||
*a = '9'; // underflow subtracting
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
xdtoa(Fmt *fmt, char *s2, double f)
|
||||
{
|
||||
char s1[NSIGNIF+10];
|
||||
double g, h;
|
||||
int e, d, i, n;
|
||||
int c1, c2, c3, c4, ucase, sign, chr, prec;
|
||||
|
||||
prec = FDEFLT;
|
||||
if(fmt->flags & FmtPrec)
|
||||
prec = fmt->prec;
|
||||
if(prec > FDIGIT)
|
||||
prec = FDIGIT;
|
||||
if(isNaN(f)) {
|
||||
strcpy(s2, "NaN");
|
||||
return;
|
||||
}
|
||||
if(isInf(f, 1)) {
|
||||
strcpy(s2, "+Inf");
|
||||
return;
|
||||
}
|
||||
if(isInf(f, -1)) {
|
||||
strcpy(s2, "-Inf");
|
||||
return;
|
||||
}
|
||||
sign = 0;
|
||||
if(f < 0) {
|
||||
f = -f;
|
||||
sign++;
|
||||
}
|
||||
ucase = 0;
|
||||
chr = fmt->r;
|
||||
if(isupper(chr)) {
|
||||
ucase = 1;
|
||||
chr = tolower(chr);
|
||||
}
|
||||
|
||||
e = 0;
|
||||
g = f;
|
||||
if(g != 0) {
|
||||
frexp(f, &e);
|
||||
e = e * .301029995664;
|
||||
if(e >= -150 && e <= +150) {
|
||||
d = 0;
|
||||
h = f;
|
||||
} else {
|
||||
d = e/2;
|
||||
h = f * pow10(-d);
|
||||
}
|
||||
g = h * pow10(d-e);
|
||||
while(g < 1) {
|
||||
e--;
|
||||
g = h * pow10(d-e);
|
||||
}
|
||||
while(g >= 10) {
|
||||
e++;
|
||||
g = h * pow10(d-e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* convert NSIGNIF digits and convert
|
||||
* back to get accuracy.
|
||||
*/
|
||||
for(i=0; i<NSIGNIF; i++) {
|
||||
d = g;
|
||||
s1[i] = d + '0';
|
||||
g = (g - d) * 10;
|
||||
}
|
||||
s1[i] = 0;
|
||||
|
||||
/*
|
||||
* try decimal rounding to eliminate 9s
|
||||
*/
|
||||
c2 = prec + 1;
|
||||
if(chr == 'f')
|
||||
c2 += e;
|
||||
if(c2 >= NSIGNIF-2) {
|
||||
strcpy(s2, s1);
|
||||
d = e;
|
||||
s1[NSIGNIF-2] = '0';
|
||||
s1[NSIGNIF-1] = '0';
|
||||
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
|
||||
g = strtod(s1, nil);
|
||||
if(g == f)
|
||||
goto found;
|
||||
if(xadd(s1, NSIGNIF-3, 1)) {
|
||||
e++;
|
||||
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
|
||||
}
|
||||
g = strtod(s1, nil);
|
||||
if(g == f)
|
||||
goto found;
|
||||
strcpy(s1, s2);
|
||||
e = d;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert back so s1 gets exact answer
|
||||
*/
|
||||
for(;;) {
|
||||
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
|
||||
g = strtod(s1, nil);
|
||||
if(f > g) {
|
||||
if(xadd(s1, NSIGNIF-1, 1))
|
||||
e--;
|
||||
continue;
|
||||
}
|
||||
if(f < g) {
|
||||
if(xsub(s1, NSIGNIF-1, 1))
|
||||
e++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
found:
|
||||
/*
|
||||
* sign
|
||||
*/
|
||||
d = 0;
|
||||
i = 0;
|
||||
if(sign)
|
||||
s2[d++] = '-';
|
||||
else if(fmt->flags & FmtSign)
|
||||
s2[d++] = '+';
|
||||
else if(fmt->flags & FmtSpace)
|
||||
s2[d++] = ' ';
|
||||
|
||||
/*
|
||||
* copy into final place
|
||||
* c1 digits of leading '0'
|
||||
* c2 digits from conversion
|
||||
* c3 digits of trailing '0'
|
||||
* c4 digits after '.'
|
||||
*/
|
||||
c1 = 0;
|
||||
c2 = prec + 1;
|
||||
c3 = 0;
|
||||
c4 = prec;
|
||||
switch(chr) {
|
||||
default:
|
||||
if(xadd(s1, c2, 5))
|
||||
e++;
|
||||
break;
|
||||
case 'g':
|
||||
/*
|
||||
* decide on 'e' of 'f' style convers
|
||||
*/
|
||||
if(xadd(s1, c2, 5))
|
||||
e++;
|
||||
if(e >= -5 && e <= prec) {
|
||||
c1 = -e - 1;
|
||||
c4 = prec - e;
|
||||
chr = 'h'; // flag for 'f' style
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if(xadd(s1, c2+e, 5))
|
||||
e++;
|
||||
c1 = -e;
|
||||
if(c1 > prec)
|
||||
c1 = c2;
|
||||
c2 += e;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* clean up c1 c2 and c3
|
||||
*/
|
||||
if(c1 < 0)
|
||||
c1 = 0;
|
||||
if(c2 < 0)
|
||||
c2 = 0;
|
||||
if(c2 > NSIGNIF) {
|
||||
c3 = c2-NSIGNIF;
|
||||
c2 = NSIGNIF;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy digits
|
||||
*/
|
||||
while(c1 > 0) {
|
||||
if(c1+c2+c3 == c4)
|
||||
s2[d++] = '.';
|
||||
s2[d++] = '0';
|
||||
c1--;
|
||||
}
|
||||
while(c2 > 0) {
|
||||
if(c2+c3 == c4)
|
||||
s2[d++] = '.';
|
||||
s2[d++] = s1[i++];
|
||||
c2--;
|
||||
}
|
||||
while(c3 > 0) {
|
||||
if(c3 == c4)
|
||||
s2[d++] = '.';
|
||||
s2[d++] = '0';
|
||||
c3--;
|
||||
}
|
||||
|
||||
/*
|
||||
* strip trailing '0' on g conv
|
||||
*/
|
||||
if(fmt->flags & FmtSharp) {
|
||||
if(0 == c4)
|
||||
s2[d++] = '.';
|
||||
} else
|
||||
if(chr == 'g' || chr == 'h') {
|
||||
for(n=d-1; n>=0; n--)
|
||||
if(s2[n] != '0')
|
||||
break;
|
||||
for(i=n; i>=0; i--)
|
||||
if(s2[i] == '.') {
|
||||
d = n;
|
||||
if(i != n)
|
||||
d++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(chr == 'e' || chr == 'g') {
|
||||
if(ucase)
|
||||
s2[d++] = 'E';
|
||||
else
|
||||
s2[d++] = 'e';
|
||||
c1 = e;
|
||||
if(c1 < 0) {
|
||||
s2[d++] = '-';
|
||||
c1 = -c1;
|
||||
} else
|
||||
s2[d++] = '+';
|
||||
if(c1 >= 100) {
|
||||
s2[d++] = c1/100 + '0';
|
||||
c1 = c1%100;
|
||||
}
|
||||
s2[d++] = c1/10 + '0';
|
||||
s2[d++] = c1%10 + '0';
|
||||
}
|
||||
s2[d] = 0;
|
||||
}
|
||||
|
||||
int
|
||||
_floatfmt(Fmt *fmt, double f)
|
||||
{
|
||||
char s[1+NEXP10+1+FDIGIT+1];
|
||||
|
||||
/*
|
||||
* The max length of a %f string is
|
||||
* '[+-]'+"max exponent"+'.'+"max precision"+'\0'
|
||||
* which is 341 currently.
|
||||
*/
|
||||
xdtoa(fmt, s, f);
|
||||
fmt->flags &= FmtWidth|FmtLeft;
|
||||
_fmtcpy(fmt, s, strlen(s), strlen(s));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_efgfmt(Fmt *f)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = va_arg(f->args, double);
|
||||
return _floatfmt(f, d);
|
||||
}
|
227
sys/src/libc/fmt/fmt.c
Normal file
227
sys/src/libc/fmt/fmt.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
enum
|
||||
{
|
||||
Maxfmt = 64
|
||||
};
|
||||
|
||||
typedef struct Convfmt Convfmt;
|
||||
struct Convfmt
|
||||
{
|
||||
int c;
|
||||
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
/* lock by calling _fmtlock, _fmtunlock */
|
||||
int nfmt;
|
||||
Convfmt fmt[Maxfmt];
|
||||
} fmtalloc;
|
||||
|
||||
static Convfmt knownfmt[] = {
|
||||
' ', _flagfmt,
|
||||
'#', _flagfmt,
|
||||
'%', _percentfmt,
|
||||
'+', _flagfmt,
|
||||
',', _flagfmt,
|
||||
'-', _flagfmt,
|
||||
'C', _runefmt,
|
||||
'E', _efgfmt,
|
||||
'G', _efgfmt,
|
||||
'S', _runesfmt,
|
||||
'X', _ifmt,
|
||||
'b', _ifmt,
|
||||
'c', _charfmt,
|
||||
'd', _ifmt,
|
||||
'e', _efgfmt,
|
||||
'f', _efgfmt,
|
||||
'g', _efgfmt,
|
||||
'h', _flagfmt,
|
||||
'l', _flagfmt,
|
||||
'n', _countfmt,
|
||||
'o', _ifmt,
|
||||
'p', _ifmt,
|
||||
'r', errfmt,
|
||||
's', _strfmt,
|
||||
'u', _flagfmt,
|
||||
'x', _ifmt,
|
||||
0, nil,
|
||||
};
|
||||
|
||||
int (*doquote)(int);
|
||||
|
||||
/*
|
||||
* _fmtlock() must be set
|
||||
*/
|
||||
static int
|
||||
_fmtinstall(int c, Fmts f)
|
||||
{
|
||||
Convfmt *p, *ep;
|
||||
|
||||
if(c<=0 || c>=65536)
|
||||
return -1;
|
||||
if(!f)
|
||||
f = _badfmt;
|
||||
|
||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
||||
for(p=fmtalloc.fmt; p<ep; p++)
|
||||
if(p->c == c)
|
||||
break;
|
||||
|
||||
if(p == &fmtalloc.fmt[Maxfmt])
|
||||
return -1;
|
||||
|
||||
p->fmt = f;
|
||||
if(p == ep){ /* installing a new format character */
|
||||
fmtalloc.nfmt++;
|
||||
p->c = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fmtinstall(int c, Fmts f)
|
||||
{
|
||||
int ret;
|
||||
|
||||
_fmtlock();
|
||||
ret = _fmtinstall(c, f);
|
||||
_fmtunlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Fmts
|
||||
fmtfmt(int c)
|
||||
{
|
||||
Convfmt *p, *ep;
|
||||
|
||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
||||
for(p=fmtalloc.fmt; p<ep; p++)
|
||||
if(p->c == c){
|
||||
while(p->fmt == nil) /* loop until value is updated */
|
||||
;
|
||||
return p->fmt;
|
||||
}
|
||||
|
||||
/* is this a predefined format char? */
|
||||
_fmtlock();
|
||||
for(p=knownfmt; p->c; p++)
|
||||
if(p->c == c){
|
||||
_fmtinstall(p->c, p->fmt);
|
||||
_fmtunlock();
|
||||
return p->fmt;
|
||||
}
|
||||
_fmtunlock();
|
||||
|
||||
return _badfmt;
|
||||
}
|
||||
|
||||
void*
|
||||
_fmtdispatch(Fmt *f, const void *fmt, int isrunes)
|
||||
{
|
||||
Rune rune, r;
|
||||
int i, n, w, p;
|
||||
uint32_t fl;
|
||||
const void *ret;
|
||||
|
||||
w = f->width;
|
||||
p = f->prec;
|
||||
fl = f->flags;
|
||||
|
||||
f->flags = 0;
|
||||
f->width = f->prec = 0;
|
||||
|
||||
for(;;){
|
||||
if(isrunes){
|
||||
r = *(Rune*)fmt;
|
||||
fmt = (Rune*)fmt + 1;
|
||||
}else{
|
||||
fmt = (char*)fmt + chartorune(&rune, fmt);
|
||||
r = rune;
|
||||
}
|
||||
f->r = r;
|
||||
switch(r){
|
||||
case '\0':
|
||||
ret = nil;
|
||||
goto end;
|
||||
case '.':
|
||||
f->flags |= FmtWidth|FmtPrec;
|
||||
continue;
|
||||
case '0':
|
||||
if(!(f->flags & FmtWidth)){
|
||||
f->flags |= FmtZero;
|
||||
continue;
|
||||
}
|
||||
/* fall through */
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
i = 0;
|
||||
while(r >= '0' && r <= '9'){
|
||||
i = i * 10 + r - '0';
|
||||
if(isrunes){
|
||||
r = *(Rune*)fmt;
|
||||
fmt = (Rune*)fmt + 1;
|
||||
}else{
|
||||
r = *(char*)fmt;
|
||||
fmt = (char*)fmt + 1;
|
||||
}
|
||||
}
|
||||
if(isrunes)
|
||||
fmt = (Rune*)fmt - 1;
|
||||
else
|
||||
fmt = (char*)fmt - 1;
|
||||
numflag:
|
||||
if(f->flags & FmtWidth){
|
||||
f->flags |= FmtPrec;
|
||||
f->prec = i;
|
||||
}else{
|
||||
f->flags |= FmtWidth;
|
||||
f->width = i;
|
||||
}
|
||||
continue;
|
||||
case '*':
|
||||
i = va_arg(f->args, int);
|
||||
if(i < 0){
|
||||
/*
|
||||
* negative precision =>
|
||||
* ignore the precision.
|
||||
*/
|
||||
if(f->flags & FmtPrec){
|
||||
f->flags &= ~FmtPrec;
|
||||
f->prec = 0;
|
||||
continue;
|
||||
}
|
||||
i = -i;
|
||||
f->flags |= FmtLeft;
|
||||
}
|
||||
goto numflag;
|
||||
}
|
||||
n = (*fmtfmt(r))(f);
|
||||
if(n < 0){
|
||||
ret = nil;
|
||||
break;
|
||||
}
|
||||
if(n == 0){
|
||||
ret = fmt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end:
|
||||
f->width = w;
|
||||
f->prec = p;
|
||||
f->flags = fl;
|
||||
return (void*)ret;
|
||||
}
|
94
sys/src/libc/fmt/fmtdef.h
Normal file
94
sys/src/libc/fmt/fmtdef.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* dofmt -- format to a buffer
|
||||
* the number of characters formatted is returned,
|
||||
* or -1 if there was an error.
|
||||
* if the buffer is ever filled, flush is called.
|
||||
* it should reset the buffer and return whether formatting should continue.
|
||||
*/
|
||||
|
||||
typedef int (*Fmts)(Fmt*);
|
||||
|
||||
typedef struct Quoteinfo Quoteinfo;
|
||||
struct Quoteinfo
|
||||
{
|
||||
int quoted; /* if set, string must be quoted */
|
||||
int nrunesin; /* number of input runes that can be accepted */
|
||||
int nbytesin; /* number of input bytes that can be accepted */
|
||||
int nrunesout; /* number of runes that will be generated */
|
||||
int nbytesout; /* number of bytes that will be generated */
|
||||
};
|
||||
|
||||
void *_fmtflush(Fmt*, void*, int);
|
||||
void *_fmtdispatch(Fmt*, const void*, int);
|
||||
int _floatfmt(Fmt*, double);
|
||||
int _fmtpad(Fmt*, int);
|
||||
int _rfmtpad(Fmt*, int);
|
||||
int _fmtFdFlush(Fmt*);
|
||||
|
||||
int _efgfmt(Fmt*);
|
||||
int _charfmt(Fmt*);
|
||||
int _countfmt(Fmt*);
|
||||
int _flagfmt(Fmt*);
|
||||
int _percentfmt(Fmt*);
|
||||
int _ifmt(Fmt*);
|
||||
int _runefmt(Fmt*);
|
||||
int _runesfmt(Fmt*);
|
||||
int _strfmt(Fmt*);
|
||||
int _badfmt(Fmt*);
|
||||
int _fmtcpy(Fmt*, const void*, int, int);
|
||||
int _fmtrcpy(Fmt*, const void*, int n);
|
||||
|
||||
void _fmtlock(void);
|
||||
void _fmtunlock(void);
|
||||
|
||||
#define FMTCHAR(f, t, s, c)\
|
||||
do{\
|
||||
if(t + 1 > (char*)s){\
|
||||
t = _fmtflush(f, t, 1);\
|
||||
if(t != nil)\
|
||||
s = f->stop;\
|
||||
else\
|
||||
return -1;\
|
||||
}\
|
||||
*t++ = c;\
|
||||
}while(0)
|
||||
|
||||
#define FMTRCHAR(f, t, s, c)\
|
||||
do{\
|
||||
if(t + 1 > (Rune*)s){\
|
||||
t = _fmtflush(f, t, sizeof(Rune));\
|
||||
if(t != nil)\
|
||||
s = f->stop;\
|
||||
else\
|
||||
return -1;\
|
||||
}\
|
||||
*t++ = c;\
|
||||
}while(0)
|
||||
|
||||
#define FMTRUNE(f, t, s, r)\
|
||||
do{\
|
||||
Rune _rune;\
|
||||
int _runelen;\
|
||||
if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
|
||||
t = _fmtflush(f, t, _runelen);\
|
||||
if(t != nil)\
|
||||
s = f->stop;\
|
||||
else\
|
||||
return -1;\
|
||||
}\
|
||||
if(r < Runeself)\
|
||||
*t++ = r;\
|
||||
else{\
|
||||
_rune = r;\
|
||||
t += runetochar(t, &_rune);\
|
||||
}\
|
||||
}while(0)
|
40
sys/src/libc/fmt/fmtfd.c
Normal file
40
sys/src/libc/fmt/fmtfd.c
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/*
|
||||
* public routine for final flush of a formatting buffer
|
||||
* to a file descriptor; returns total char count.
|
||||
*/
|
||||
int
|
||||
fmtfdflush(Fmt *f)
|
||||
{
|
||||
if(_fmtFdFlush(f) <= 0)
|
||||
return -1;
|
||||
return f->nfmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize an output buffer for buffered printing
|
||||
*/
|
||||
int
|
||||
fmtfdinit(Fmt *f, int fd, char *buf, int size)
|
||||
{
|
||||
f->runes = 0;
|
||||
f->start = buf;
|
||||
f->to = buf;
|
||||
f->stop = buf + size;
|
||||
f->flush = _fmtFdFlush;
|
||||
f->farg = (void*)(uintptr_t)fd;
|
||||
f->nfmt = 0;
|
||||
return 0;
|
||||
}
|
25
sys/src/libc/fmt/fmtlock.c
Normal file
25
sys/src/libc/fmt/fmtlock.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static Lock fmtl;
|
||||
|
||||
void
|
||||
_fmtlock(void)
|
||||
{
|
||||
lock(&fmtl);
|
||||
}
|
||||
|
||||
void
|
||||
_fmtunlock(void)
|
||||
{
|
||||
unlock(&fmtl);
|
||||
}
|
30
sys/src/libc/fmt/fmtprint.c
Normal file
30
sys/src/libc/fmt/fmtprint.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
|
||||
/*
|
||||
* format a string into the output buffer
|
||||
* designed for formats which themselves call fmt
|
||||
*/
|
||||
int
|
||||
fmtprint(Fmt *f, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
int n;
|
||||
|
||||
va_start(va, fmt);
|
||||
n = fmtvprint(f, fmt, va);
|
||||
va_end(va);
|
||||
return n;
|
||||
}
|
||||
|
259
sys/src/libc/fmt/fmtquote.c
Normal file
259
sys/src/libc/fmt/fmtquote.c
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/*
|
||||
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
|
||||
* How many runes? How much of the input will be consumed?
|
||||
* The parameter q is filled in by _quotesetup.
|
||||
* The string may be UTF or Runes (s or r).
|
||||
* Return count does not include NUL.
|
||||
* Terminate the scan at the first of:
|
||||
* NUL in input
|
||||
* count exceeded in input
|
||||
* count exceeded on output
|
||||
* *ninp is set to number of input bytes accepted.
|
||||
* nin may be <0 initially, to avoid checking input by count.
|
||||
*/
|
||||
void
|
||||
_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q,
|
||||
int sharp, int runesout)
|
||||
{
|
||||
int w;
|
||||
Rune c;
|
||||
|
||||
q->quoted = 0;
|
||||
q->nbytesout = 0;
|
||||
q->nrunesout = 0;
|
||||
q->nbytesin = 0;
|
||||
q->nrunesin = 0;
|
||||
if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
|
||||
if(nout < 2)
|
||||
return;
|
||||
q->quoted = 1;
|
||||
q->nbytesout = 2;
|
||||
q->nrunesout = 2;
|
||||
}
|
||||
for(; nin!=0; nin--){
|
||||
if(s)
|
||||
w = chartorune(&c, s);
|
||||
else{
|
||||
c = *r;
|
||||
w = runelen(c);
|
||||
}
|
||||
|
||||
if(c == '\0')
|
||||
break;
|
||||
if(runesout){
|
||||
if(q->nrunesout+1 > nout)
|
||||
break;
|
||||
}else{
|
||||
if(q->nbytesout+w > nout)
|
||||
break;
|
||||
}
|
||||
|
||||
if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
|
||||
if(!q->quoted){
|
||||
if(runesout){
|
||||
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
|
||||
break;
|
||||
}else{
|
||||
if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
|
||||
break;
|
||||
}
|
||||
q->nrunesout += 2; /* include quotes */
|
||||
q->nbytesout += 2; /* include quotes */
|
||||
q->quoted = 1;
|
||||
}
|
||||
if(c == '\'') {
|
||||
if(runesout){
|
||||
if(1+q->nrunesout+1 > nout) /* no room for quotes */
|
||||
break;
|
||||
}else{
|
||||
if(1+q->nbytesout+w > nout) /* no room for quotes */
|
||||
break;
|
||||
}
|
||||
q->nbytesout++;
|
||||
q->nrunesout++; /* quotes reproduce as two characters */
|
||||
}
|
||||
}
|
||||
|
||||
/* advance input */
|
||||
if(s)
|
||||
s += w;
|
||||
else
|
||||
r++;
|
||||
q->nbytesin += w;
|
||||
q->nrunesin++;
|
||||
|
||||
/* advance output */
|
||||
q->nbytesout += w;
|
||||
q->nrunesout++;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
|
||||
{
|
||||
Rune r, *rm, *rme;
|
||||
char *t, *s, *m, *me;
|
||||
Rune *rt, *rs;
|
||||
uint32_t fl;
|
||||
int nc, w;
|
||||
|
||||
m = sin;
|
||||
me = m + q->nbytesin;
|
||||
rm = rin;
|
||||
rme = rm + q->nrunesin;
|
||||
|
||||
w = f->width;
|
||||
fl = f->flags;
|
||||
if(f->runes){
|
||||
if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
|
||||
return -1;
|
||||
}else{
|
||||
if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
|
||||
return -1;
|
||||
}
|
||||
t = f->to;
|
||||
s = f->stop;
|
||||
rt = f->to;
|
||||
rs = f->stop;
|
||||
if(f->runes)
|
||||
FMTRCHAR(f, rt, rs, '\'');
|
||||
else
|
||||
FMTRUNE(f, t, s, '\'');
|
||||
for(nc = q->nrunesin; nc > 0; nc--){
|
||||
if(sin){
|
||||
r = *(uint8_t*)m;
|
||||
if(r < Runeself)
|
||||
m++;
|
||||
else if((me - m) >= UTFmax || fullrune(m, me-m))
|
||||
m += chartorune(&r, m);
|
||||
else
|
||||
break;
|
||||
}else{
|
||||
if(rm >= rme)
|
||||
break;
|
||||
r = *(uint8_t*)rm++;
|
||||
}
|
||||
if(f->runes){
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
if(r == '\'')
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
}else{
|
||||
FMTRUNE(f, t, s, r);
|
||||
if(r == '\'')
|
||||
FMTRUNE(f, t, s, r);
|
||||
}
|
||||
}
|
||||
|
||||
if(f->runes){
|
||||
FMTRCHAR(f, rt, rs, '\'');
|
||||
USED(rs);
|
||||
f->nfmt += rt - (Rune *)f->to;
|
||||
f->to = rt;
|
||||
if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
|
||||
return -1;
|
||||
}else{
|
||||
FMTRUNE(f, t, s, '\'');
|
||||
USED(s);
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_quotestrfmt(int runesin, Fmt *f)
|
||||
{
|
||||
int nin, outlen;
|
||||
Rune *r;
|
||||
char *s;
|
||||
Quoteinfo q;
|
||||
|
||||
nin = -1;
|
||||
if(f->flags&FmtPrec)
|
||||
nin = f->prec;
|
||||
if(runesin){
|
||||
r = va_arg(f->args, Rune *);
|
||||
s = nil;
|
||||
}else{
|
||||
s = va_arg(f->args, char *);
|
||||
r = nil;
|
||||
}
|
||||
if(!s && !r)
|
||||
return _fmtcpy(f, "<nil>", 5, 5);
|
||||
|
||||
if(f->flush)
|
||||
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
|
||||
else if(f->runes)
|
||||
outlen = (Rune*)f->stop - (Rune*)f->to;
|
||||
else
|
||||
outlen = (char*)f->stop - (char*)f->to;
|
||||
|
||||
_quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
|
||||
//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
|
||||
|
||||
if(runesin){
|
||||
if(!q.quoted)
|
||||
return _fmtrcpy(f, r, q.nrunesin);
|
||||
return qstrfmt(nil, r, &q, f);
|
||||
}
|
||||
|
||||
if(!q.quoted)
|
||||
return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
|
||||
return qstrfmt(s, nil, &q, f);
|
||||
}
|
||||
|
||||
int
|
||||
quotestrfmt(Fmt *f)
|
||||
{
|
||||
return _quotestrfmt(0, f);
|
||||
}
|
||||
|
||||
int
|
||||
quoterunestrfmt(Fmt *f)
|
||||
{
|
||||
return _quotestrfmt(1, f);
|
||||
}
|
||||
|
||||
void
|
||||
quotefmtinstall(void)
|
||||
{
|
||||
fmtinstall('q', quotestrfmt);
|
||||
fmtinstall('Q', quoterunestrfmt);
|
||||
}
|
||||
|
||||
int
|
||||
_needsquotes(char *s, int *quotelenp)
|
||||
{
|
||||
Quoteinfo q;
|
||||
|
||||
_quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
|
||||
*quotelenp = q.nbytesout;
|
||||
|
||||
return q.quoted;
|
||||
}
|
||||
|
||||
int
|
||||
_runeneedsquotes(Rune *r, int *quotelenp)
|
||||
{
|
||||
Quoteinfo q;
|
||||
|
||||
_quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
|
||||
*quotelenp = q.nrunesout;
|
||||
|
||||
return q.quoted;
|
||||
}
|
34
sys/src/libc/fmt/fmtrune.c
Normal file
34
sys/src/libc/fmt/fmtrune.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
int
|
||||
fmtrune(Fmt *f, int r)
|
||||
{
|
||||
Rune *rt;
|
||||
char *t;
|
||||
int n;
|
||||
|
||||
if(f->runes){
|
||||
rt = f->to;
|
||||
FMTRCHAR(f, rt, f->stop, r);
|
||||
f->to = rt;
|
||||
n = 1;
|
||||
}else{
|
||||
t = f->to;
|
||||
FMTRUNE(f, t, f->stop, r);
|
||||
n = t - (char*)f->to;
|
||||
f->to = t;
|
||||
}
|
||||
f->nfmt += n;
|
||||
return 0;
|
||||
}
|
20
sys/src/libc/fmt/fmtstr.c
Normal file
20
sys/src/libc/fmt/fmtstr.c
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
fmtstrflush(Fmt *f)
|
||||
{
|
||||
if(f->start == nil)
|
||||
return nil;
|
||||
*(char*)f->to = '\0';
|
||||
return f->start;
|
||||
}
|
39
sys/src/libc/fmt/fmtvprint.c
Normal file
39
sys/src/libc/fmt/fmtvprint.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
|
||||
/*
|
||||
* format a string into the output buffer
|
||||
* designed for formats which themselves call fmt
|
||||
*/
|
||||
int
|
||||
fmtvprint(Fmt *f, const char *fmt, va_list args)
|
||||
{
|
||||
va_list va;
|
||||
int n;
|
||||
|
||||
//va = f->args;
|
||||
//f->args = args;
|
||||
va_copy(va,f->args);
|
||||
va_end(f->args);
|
||||
va_copy(f->args,args);
|
||||
n = dofmt(f, fmt);
|
||||
va_end(f->args);
|
||||
va_copy(f->args,va);
|
||||
va_end(va);
|
||||
//f->args = va;
|
||||
if(n >= 0)
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
23
sys/src/libc/fmt/fprint.c
Normal file
23
sys/src/libc/fmt/fprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
fprint(int fd, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vfprint(fd, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
23
sys/src/libc/fmt/print.c
Normal file
23
sys/src/libc/fmt/print.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
print(const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vfprint(1, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
20
sys/src/libc/fmt/runefmtstr.c
Normal file
20
sys/src/libc/fmt/runefmtstr.c
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runefmtstrflush(Fmt *f)
|
||||
{
|
||||
if(f->start == nil)
|
||||
return nil;
|
||||
*(Rune*)f->to = '\0';
|
||||
return f->start;
|
||||
}
|
23
sys/src/libc/fmt/runeseprint.c
Normal file
23
sys/src/libc/fmt/runeseprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runeseprint(Rune *buf, Rune *e, const char *fmt, ...)
|
||||
{
|
||||
Rune *p;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = runevseprint(buf, e, fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
23
sys/src/libc/fmt/runesmprint.c
Normal file
23
sys/src/libc/fmt/runesmprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runesmprint(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
Rune *p;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = runevsmprint(fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
24
sys/src/libc/fmt/runesnprint.c
Normal file
24
sys/src/libc/fmt/runesnprint.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runesnprint(Rune *buf, int len, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = runevsnprint(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
||||
|
23
sys/src/libc/fmt/runesprint.c
Normal file
23
sys/src/libc/fmt/runesprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runesprint(Rune *buf, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = runevsnprint(buf, 256, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
34
sys/src/libc/fmt/runevseprint.c
Normal file
34
sys/src/libc/fmt/runevseprint.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runevseprint(Rune *buf, Rune *e, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(e <= buf)
|
||||
return nil;
|
||||
f.runes = 1;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = e - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
*(Rune*)f.to = '\0';
|
||||
return f.to;
|
||||
}
|
||||
|
83
sys/src/libc/fmt/runevsmprint.c
Normal file
83
sys/src/libc/fmt/runevsmprint.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
static int
|
||||
runeFmtStrFlush(Fmt *f)
|
||||
{
|
||||
Rune *s;
|
||||
int n;
|
||||
|
||||
if(f->start == nil)
|
||||
return 0;
|
||||
n = (int)(uintptr)f->farg;
|
||||
n *= 2;
|
||||
s = f->start;
|
||||
f->start = realloc(s, sizeof(Rune)*n);
|
||||
if(f->start == nil){
|
||||
f->farg = nil;
|
||||
f->to = nil;
|
||||
f->stop = nil;
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
f->farg = (void*)(uintptr_t)n;
|
||||
f->to = (Rune*)f->start + ((Rune*)f->to - s);
|
||||
f->stop = (Rune*)f->start + n - 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
runefmtstrinit(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
memset(f, 0, sizeof *f);
|
||||
f->runes = 1;
|
||||
n = 32;
|
||||
f->start = malloc(sizeof(Rune)*n);
|
||||
if(f->start == nil)
|
||||
return -1;
|
||||
setmalloctag(f->start, getcallerpc());
|
||||
f->to = f->start;
|
||||
f->stop = (Rune*)f->start + n - 1;
|
||||
f->flush = runeFmtStrFlush;
|
||||
f->farg = (void*)(uintptr_t)n;
|
||||
f->nfmt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* print into an allocated string buffer
|
||||
*/
|
||||
Rune*
|
||||
runevsmprint(const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
int n;
|
||||
|
||||
if(runefmtstrinit(&f) < 0)
|
||||
return nil;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
n = dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
if(f.start == nil) /* realloc failed? */
|
||||
return nil;
|
||||
if(n < 0){
|
||||
free(f.start);
|
||||
return nil;
|
||||
}
|
||||
setmalloctag(f.start, getcallerpc());
|
||||
*(Rune*)f.to = '\0';
|
||||
return f.start;
|
||||
}
|
33
sys/src/libc/fmt/runevsnprint.c
Normal file
33
sys/src/libc/fmt/runevsnprint.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runevsnprint(Rune *buf, int len, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(len <= 0)
|
||||
return -1;
|
||||
f.runes = 1;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = buf + len - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
*(Rune*)f.to = '\0';
|
||||
return (Rune*)f.to - buf;
|
||||
}
|
23
sys/src/libc/fmt/seprint.c
Normal file
23
sys/src/libc/fmt/seprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
seprint(char *buf, char *e, const char *fmt, ...)
|
||||
{
|
||||
char *p;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = vseprint(buf, e, fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
24
sys/src/libc/fmt/smprint.c
Normal file
24
sys/src/libc/fmt/smprint.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
smprint(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *p;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = vsmprint(fmt, args);
|
||||
va_end(args);
|
||||
setmalloctag(p, getcallerpc());
|
||||
return p;
|
||||
}
|
24
sys/src/libc/fmt/snprint.c
Normal file
24
sys/src/libc/fmt/snprint.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
snprint(char *buf, int len, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vsnprint(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
||||
|
23
sys/src/libc/fmt/sprint.c
Normal file
23
sys/src/libc/fmt/sprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
sprint(char *buf, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vsnprint(buf, 65536, fmt, args); /* big number, but sprint is deprecated anyway */
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
45
sys/src/libc/fmt/vfprint.c
Normal file
45
sys/src/libc/fmt/vfprint.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/*
|
||||
* generic routine for flushing a formatting buffer
|
||||
* to a file descriptor
|
||||
*/
|
||||
int
|
||||
_fmtFdFlush(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = (char*)f->to - (char*)f->start;
|
||||
if(n && write((int)(uintptr)f->farg, f->start, n) != n)
|
||||
return 0;
|
||||
f->to = f->start;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
vfprint(int fd, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
char buf[256];
|
||||
int n;
|
||||
|
||||
fmtfdinit(&f, fd, buf, sizeof(buf));
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
n = dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
if(n > 0 && _fmtFdFlush(&f) == 0)
|
||||
return -1;
|
||||
return n;
|
||||
}
|
34
sys/src/libc/fmt/vseprint.c
Normal file
34
sys/src/libc/fmt/vseprint.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
vseprint(char *buf, char *e, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(e <= buf)
|
||||
return nil;
|
||||
f.runes = 0;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = e - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
*(char*)f.to = '\0';
|
||||
return f.to;
|
||||
}
|
||||
|
85
sys/src/libc/fmt/vsmprint.c
Normal file
85
sys/src/libc/fmt/vsmprint.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
static int
|
||||
fmtStrFlush(Fmt *f)
|
||||
{
|
||||
char *s;
|
||||
int n;
|
||||
|
||||
if(f->start == nil)
|
||||
return 0;
|
||||
n = (int)(uintptr)f->farg;
|
||||
n *= 2;
|
||||
s = f->start;
|
||||
f->start = realloc(s, n);
|
||||
if(f->start == nil){
|
||||
f->farg = nil;
|
||||
f->to = nil;
|
||||
f->stop = nil;
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
f->farg = (void*)(uintptr_t)n;
|
||||
f->to = (char*)f->start + ((char*)f->to - s);
|
||||
f->stop = (char*)f->start + n - 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fmtstrinit(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
memset(f, 0, sizeof *f);
|
||||
f->runes = 0;
|
||||
n = 32;
|
||||
/* this should not be necessary */
|
||||
n = 4096;
|
||||
f->start = malloc(n);
|
||||
if(f->start == nil)
|
||||
return -1;
|
||||
setmalloctag(f->start, getcallerpc());
|
||||
f->to = f->start;
|
||||
f->stop = (char*)f->start + n - 1;
|
||||
f->flush = fmtStrFlush;
|
||||
f->farg = (void*)(uintptr_t)n;
|
||||
f->nfmt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* print into an allocated string buffer
|
||||
*/
|
||||
char*
|
||||
vsmprint(const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
int n;
|
||||
|
||||
if(fmtstrinit(&f) < 0)
|
||||
return nil;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
n = dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
if(f.start == nil) /* realloc failed? */
|
||||
return nil;
|
||||
if(n < 0){
|
||||
free(f.start);
|
||||
return nil;
|
||||
}
|
||||
setmalloctag(f.start, getcallerpc());
|
||||
*(char*)f.to = '\0';
|
||||
return f.start;
|
||||
}
|
33
sys/src/libc/fmt/vsnprint.c
Normal file
33
sys/src/libc/fmt/vsnprint.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
vsnprint(char *buf, int len, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(len <= 0)
|
||||
return -1;
|
||||
f.runes = 0;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = buf + len - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
*(char*)f.to = '\0';
|
||||
return (char*)f.to - buf;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user