Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'buffile' into p2

Fixed conflicts:
	.gitmodules
	3rd/libtommath
	core/potion.h
  • Loading branch information...
commit 90334e0a6bd6592085928d6869161c7990321488 2 parents a419eb6 + 631a8d2
@rurban rurban authored
View
7 .gitmodules
@@ -1,9 +1,10 @@
[submodule "3rd/libuv"]
path = 3rd/libuv
url = git://github.com/joyent/libuv.git
-[submodule "3rd/sregex"]
- path = 3rd/sregex
- url = git://github.com/agentzh/sregex.git
[submodule "3rd/libtommath"]
path = 3rd/libtommath
url = git://github.com/libtom/libtommath.git
+[submodule "3rd/pcre"]
+ path = 3rd/pcre
+ url = git://github.com/Distrotech/pcre.git
+ branch = master
1  3rd/pcre
@@ -0,0 +1 @@
+Subproject commit 000f53cf12bbfb4f658d2417a96e03cb3c0b97cc
1  3rd/sregex
@@ -1 +0,0 @@
-Subproject commit 2d2622e960f3d71772c27569f43dee05bfdb28a6
View
59 Makefile
@@ -52,14 +52,14 @@ DOCHTML = ${DOC:.textile=.html}
BINS = bin/potion${EXE} bin/p2${EXE}
PLIBS = $(foreach l,potion p2,lib/lib$l${DLL})
PLIBS += $(foreach s,syntax syntax-p5,lib/potion/lib$s${DLL})
-#EXTLIBS = $(foreach m,sregex uv,lib/lib$m.a)
-DYNLIBS = $(foreach m,readline libtommath m_apm,lib/potion/$m${LOADEXT})
+#EXTLIBS = $(foreach m,uv pcre,lib/lib$m.a)
+#EXTLIBS = -L3rd/pcre -lpcre -L3rd/libuv -luv -L3rd/libtommath -llibtommath
+DYNLIBS = $(foreach m,readline buffile,lib/potion/$m${LOADEXT})
OBJS = .o .o2
ifneq (${FPIC},)
OBJS += ${OPIC} ${OPIC}2
endif
-
GREGCFLAGS = -O3 -DNDEBUG
CAT = /bin/cat
ECHO ?= /bin/echo
@@ -78,7 +78,7 @@ default: pn p2
all: default libs static doc test
bins: ${BINS}
-libs: ${PLIBS}
+libs: ${PLIBS} ${DYNLIBS}
pn: bin/potion${EXE} libs
p2: bin/p2${EXE} libs
static: lib/libpotion.a bin/potion-s${EXE} lib/libp2.a bin/p2-s${EXE}
@@ -250,7 +250,7 @@ bin/potion-s${EXE}: ${OBJ_POTION} lib/libpotion.a
@[ -d bin ] || mkdir bin
@${CC} ${CFLAGS} ${OBJ_POTION} -o $@ ${LIBPTH} lib/libpotion.a ${LIBS}
-bin/p2-s${EXE}: ${OBJ_P2} lib/libp2.a ${EXTLIBS}
+bin/p2-s${EXE}: ${OBJ_P2} lib/libp2.a
@${ECHO} LINK $@
@[ -d bin ] || mkdir bin
@${CC} ${CFLAGS} ${OBJ_P2} -o $@ ${LIBPTH} lib/libp2.a ${LIBS} ${EXTLIBS}
@@ -277,7 +277,7 @@ lib/libpotion${DLL}: ${PIC_OBJ} ${PIC_OBJ_SYN} core/config.h core/potion.h
${PIC_OBJ} ${PIC_OBJ_SYN} ${LIBS} > /dev/null
@if [ x${DLL} = x.dll ]; then cp $@ bin/; fi
-lib/libp2${DLL}: $(subst .${OPIC},.${OPIC}2,${PIC_OBJ}) ${PIC_OBJ_P2_SYN} core/config.h core/potion.h ${EXTLIBS}
+lib/libp2${DLL}: $(subst .${OPIC},.${OPIC}2,${PIC_OBJ}) ${PIC_OBJ_P2_SYN} core/config.h core/potion.h
@${ECHO} LD $@
@[ -d lib/potion ] || mkdir lib/potion
@if [ -e $@ ]; then rm -f $@; fi
@@ -297,19 +297,31 @@ lib/potion/libsyntax-p5${DLL}: syn/syntax-p5.${OPIC}2
@${CC} ${DEBUGFLAGS} -o $@ $(INCS) ${LDDLLFLAGS} ${RPATH} \
$< ${LIBPTH} -lp2 $(LIBS)
-# 3rdparty EXTLIBS linked
+# 3rdparty EXTLIBS statically linked
lib/libuv.a: core/config.h core/potion.h \
3rd/libuv/Makefile
@${ECHO} MAKE $@
@${MAKE} -s -C 3rd/libuv libuv${DLL}
@cp 3rd/libuv/libuv.a lib/
+3rd/libuv/libuv$(DLL): core/config.h core/potion.h \
+ 3rd/libuv/Makefile
+ @${ECHO} MAKE $@
+ @${MAKE} -s -C 3rd/libuv libuv${DLL}
+ @cp 3rd/libuv/libuv$(DLL) lib/
+
lib/libsregex.a: core/config.h core/potion.h \
3rd/sregex/Makefile
@${ECHO} MAKE $@
@${MAKE} -s -C 3rd/sregex CC="${CC}"
@cp 3rd/sregex/libsregex.a lib/
+lib/libpcre.a: core/config.h core/potion.h \
+ 3rd/pcre/Makefile
+ @${ECHO} MAKE $@
+ @${MAKE} -s -C 3rd/pcre CC="${CC}"
+ @cp 3rd/pcre/libpcre.a lib/
+
# DYNLIBS
lib/potion/readline${LOADEXT}: core/config.h core/potion.h \
lib/readline/Makefile lib/readline/linenoise.c \
@@ -319,6 +331,29 @@ lib/potion/readline${LOADEXT}: core/config.h core/potion.h \
@[ -d lib/potion ] || mkdir lib/potion
@cp lib/readline/readline${LOADEXT} $@
+lib/potion/buffile${LOADEXT}: core/config.h core/potion.h \
+ lib/buffile.${OPIC}2 lib/buffile.c
+ @${ECHO} LD $@
+ @[ -d lib/potion ] || mkdir lib/potion
+ @${CC} $(DEBUGFLAGS) -o $@ ${LDDLLFLAGS} \
+ lib/buffile.${OPIC}2 ${LIBPTH} ${LIBS} > /dev/null
+
+lib/potion/aio${LOADEXT}: core/config.h core/potion.h \
+ lib/aio.c
+ @[ -d lib/potion ] || mkdir lib/potion
+ @${ECHO} CC lib/aio.${OPIC}2
+ @${CC} -c -DP2 ${FPIC} ${CFLAGS} ${INCS} -I3rd/libuv/include -o lib/aio.${OPIC}2 lib/aio.c > /dev/null
+ @${ECHO} LD $@
+ @${CC} $(DEBUGFLAGS) -o $@ $(subst libpotion,aio,${LDDLLFLAGS}) \
+ lib/aio.${OPIC}2 ${LIBS} ${EXTLIBS} > /dev/null
+
+lib/potion/pcre${LOADEXT}: core/config.h core/potion.h \
+ lib/pcre/Makefile lib/pcre/pcre.c
+ @${ECHO} MAKE $@
+ @${MAKE} -s -C lib/pcre
+ @[ -d lib/potion ] || mkdir lib/potion
+ @cp lib/pcre/pcre${LOADEXT} $@
+
lib/potion/m_apm${LOADEXT}: core/config.h core/potion.h \
lib/m_apm/Makefile
@${ECHO} MAKE $@
@@ -339,8 +374,8 @@ bench: bin/gc-bench${EXE} bin/potion${EXE}
${ECHO} running GC benchmark; \
time bin/gc-bench
-check: test.pn test.p2
-test: test.pn test.p2
+check: libs test.pn test.p2
+test: libs test.pn test.p2
test.pn: bin/potion${EXE} bin/potion-test${EXE}
@${ECHO}; \
@@ -460,15 +495,15 @@ bin/potion-test${EXE}: ${OBJ_TEST} lib/libpotion.a
@if ${CC} ${CFLAGS} ${OBJ_TEST} -o $@ lib/libpotion.a ${LIBS}; then true; else \
${CC} ${CFLAGS} ${OBJ_TEST} -o $@ ${OBJ} ${OBJ_SYN} ${LIBS}; fi
-bin/gc-test${EXE}: ${OBJ_GC_TEST} lib/libp2.a ${EXTLIBS}
+bin/gc-test${EXE}: ${OBJ_GC_TEST} lib/libp2.a
@${ECHO} LINK $@
@${CC} ${CFLAGS} ${OBJ_GC_TEST} -o $@ lib/libp2.a ${LIBS} ${EXTLIBS}
-bin/gc-bench${EXE}: ${OBJ_GC_BENCH} lib/libp2.a ${EXTLIBS}
+bin/gc-bench${EXE}: ${OBJ_GC_BENCH} lib/libp2.a
@${ECHO} LINK $@
@${CC} ${CFLAGS} ${OBJ_GC_BENCH} -o $@ lib/libp2.a ${LIBS} ${EXTLIBS}
-bin/p2-test${EXE}: ${OBJ_P2_TEST} lib/libp2.a ${EXTLIBS}
+bin/p2-test${EXE}: ${OBJ_P2_TEST} lib/libp2.a
@${ECHO} LINK $@
@if ${CC} ${CFLAGS} ${OBJ_P2_TEST} -o $@ lib/libp2.a ${LIBS} ${EXTLIBS}; then true; else \
${CC} ${CFLAGS} ${OBJ_P2_TEST} -o $@ ${OBJ2} ${OBJ_P2_SYN} ${LIBS} ${EXTLIBS}; fi
View
134 core/file.c
@@ -1,13 +1,22 @@
-///\file file.c
-/// PNFile class for file descriptors
-//
-// (c) 2008 why the lucky stiff, the freelance professor
-//
+/** \file file.c
+ PNFile class for unbuffered blocking file descriptor IO.
+
+ Only raw and fast POSIX open,read,write,seek calls on fd.
+ fgets (aka readline) is only supported on stdin via the \c "read" method.
+ \seealso http://stackoverflow.com/questions/1658476/c-fopen-vs-open
+
+ \see the \c buffile library (PNBufFile) for buffered io via FILE*
+ for fopen, fscanf, fprintf, fread, fgets see there.
+ \see the aio library (PNAio) for async non-blocking io, via libuv bindings.
+
+ (c) 2008 why the lucky stiff, the freelance professor */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
#include "p2.h"
#include "internal.h"
#include "table.h"
@@ -22,11 +31,17 @@
typedef vPN(File) pn_file;
-///\memberof PNFile
-/// constructor method. opens a file with 0755 and returns the created PNFile
-///\param path PNString
-///\param modestr PNString r,r+,w,w+,a,a+
-///\return self or PN_NIL
+PN potion_io_error(Potion *P, PN msg) {
+ return potion_error(P, potion_str_format(P, "Error %s: %s", PN_STR_PTR(msg), strerror(errno)),
+ 0, 0, 0);
+}
+
+
+/**\memberof PNFile
+ constructor method. opens a file with 0755 and returns the created PNFile
+ \param path PNString
+ \param modestr PNString r,r+,w,w+,a,a+
+ \return self or PN_NIL */
PN potion_file_new(Potion *P, PN cl, PN self, PN path, PN modestr) {
int fd;
mode_t mode;
@@ -46,21 +61,18 @@ PN potion_file_new(Potion *P, PN cl, PN self, PN path, PN modestr) {
// invalid mode
return PN_NIL;
}
- if ((fd = open(PN_STR_PTR(path), mode, 0755)) == -1) {
- perror("open");
- // TODO: error, perm
- return PN_NIL;
- }
+ if ((fd = open(PN_STR_PTR(path), mode, 0755)) == -1)
+ return potion_io_error(P, PN_STR("open"));
((struct PNFile *)self)->fd = fd;
((struct PNFile *)self)->path = path;
((struct PNFile *)self)->mode = mode;
return self;
}
-///\memberof PNFile
-/// "fd" class method.
-///\param fd PNNumber
-///\return a new PNFile object for the already opened file descriptor (sorry, empty path).
+/**\memberof PNFile
+ \c "fd" class method.
+ \param fd PNNumber
+ \return a new PNFile object for the already opened file descriptor (sorry, empty path). */
PN potion_file_with_fd(Potion *P, PN cl, PN self, PN fd) {
struct PNFile *file = (struct PNFile *)potion_object_new(P, PN_NIL, PN_VTABLE(PN_TFILE));
file->fd = PN_INT(fd);
@@ -75,49 +87,82 @@ PN potion_file_with_fd(Potion *P, PN cl, PN self, PN fd) {
return (PN)file;
}
-///\memberof PNFile
-/// "close" method.
-///\return PN_NIL
+/**\memberof PNFile
+ \c "close" the file
+ \return PN_NIL */
PN potion_file_close(Potion *P, PN cl, pn_file self) {
- close(self->fd);
+ int retval;
+ while (retval = close(self->fd), retval == -1 && errno == EINTR) ;
self->fd = -1;
return PN_NIL;
}
-///\memberof PNFile
-/// "read" method.
-///\param n PNNumber
-///\return n PNBytes
+/**\memberof PNFile
+ \c "read" n PNBytes from the file
+ \param n PNNumber
+ \return n PNBytes */
PN potion_file_read(Potion *P, PN cl, pn_file self, PN n) {
n = PN_INT(n);
char buf[n];
int r = read(self->fd, buf, n);
if (r == -1) {
- perror("read");
+ return potion_io_error(P, PN_STR("read"));
+ //perror("read");
// TODO: error
- return PN_NUM(-1);
+ //return PN_NUM(-1);
} else if (r == 0) {
return PN_NIL;
}
return potion_byte_str2(P, buf, r);
}
-///\memberof PNFile
-/// "write" method.
-///\param str PNString
-///\return PNNumber written bytes or PN_NIL
-PN potion_file_write(Potion *P, PN cl, pn_file self, PN str) {
- int r = write(self->fd, PN_STR_PTR(str), PN_STR_LEN(str));
- if (r == -1) {
- perror("write");
- // TODO: error
- return PN_NIL;
+/**\memberof PNFile
+ \c "write" a binary representation of obj to the file handle.
+ \param obj PNString, PNBytes, PNNumber (long or double), PNBoolean (char 0 or 1)
+ \return PNNumber written bytes or PN_NIL */
+PN potion_file_write(Potion *P, PN cl, pn_file self, PN obj) {
+ long len = 0;
+ char *ptr = NULL;
+ //TODO: maybe extract ptr+len to seperate function
+ if (!PN_IS_PTR(obj)) {
+ if (!obj) return PN_NIL; //silent
+ else if (PN_IS_NUM(obj)) {
+ long tmp = PN_NUM(obj); len = sizeof(tmp); ptr = (char *)&tmp;
+ }
+ else if (PN_IS_BOOL(obj)) {
+ char tmp = (obj == PN_TRUE) ? 1 : 0; len = 1; ptr = (char *)&tmp;
+ }
+ else {
+ assert(0 && "Invalid primitive type");
+ }
+ } else {
+ switch (PN_TYPE(obj)) {
+ case PN_TSTRING: len = PN_STR_LEN(obj); ptr = PN_STR_PTR(obj); break;
+ case PN_TBYTES: len = potion_send(obj, PN_STR("length")); ptr = PN_STR_PTR(obj); break;
+ case PN_TNUMBER: {
+ double tmp = PN_DBL(obj); len = sizeof(tmp); ptr = (char *)&tmp;
+ break;
+ }
+ default: return potion_type_error(P, obj);
+ }
}
+ int r = write(self->fd, ptr, len);
+ if (r == -1)
+ return potion_io_error(P, PN_STR("write"));
return PN_NUM(r);
}
-///\memberof PNFile
-/// "string" method. some internal descr
+/**\memberof PNFile
+ \c "print" a stringification of any object to the filehandle.
+ Note that \c write prints the binary value of the object.
+ \param obj any
+ \return PN_NIL */
+PN potion_file_print(Potion *P, PN cl, pn_file self, PN obj) {
+ return potion_file_write(P, cl, self, potion_send(obj, PN_string));
+}
+
+/**\memberof PNFile
+ "string" method. some internal descr */
PN potion_file_string(Potion *P, PN cl, pn_file self) {
int fd = self->fd, rv;
char *buf;
@@ -135,9 +180,9 @@ PN potion_file_string(Potion *P, PN cl, pn_file self) {
return str;
}
-/// memberof Lobby
-/// global "read" method, read next line from stdin via fgets()
-///\return PNString or or PN_NIL
+/**\memberof Lobby
+ global "read" method, read next line from stdin via fgets()
+ \return PNString or or PN_NIL */
PN potion_lobby_read(Potion *P, PN cl, PN self) {
const int linemax = 1024;
char line[linemax];
@@ -171,4 +216,5 @@ void potion_file_init(Potion *P) {
potion_method(file_vt, "close", potion_file_close, 0);
potion_method(file_vt, "read", potion_file_read, "n=N");
potion_method(file_vt, "write", potion_file_write, "str=S");
+ potion_method(file_vt, "print", potion_file_print, "obj=o");
}
View
13 core/internal.c
@@ -237,6 +237,19 @@ void potion_error_init(Potion *P) {
potion_method(err_vt, "string", potion_error_string, 0);
}
+static inline char *potion_type_name(Potion *P, PN obj) {
+ return PN_IS_PTR(obj)
+ ? AS_STR(potion_send(PN_VTABLE(obj), PN_name))
+ : PN_IS_NIL(obj) ? "nil"
+ : PN_IS_NUM(obj) ? "Number"
+ : "Boolean";
+}
+
+PN potion_type_error(Potion *P, PN obj) {
+ return potion_error(P, potion_str_format(P, "Invalid type %s", potion_type_name(P, obj)),
+ 0, 0, 0);
+}
+
#define PN_EXIT_ERROR 1
#define PN_EXIT_FATAL 2
View
5 core/objmodel.c
@@ -485,10 +485,9 @@ PN potion_lobby_kind(Potion *P, PN cl, PN self) {
/**\memberof Lobby
\c "can" the object call the named method?
- same as potion_bind().
- \return the found method or nil */
+ \return true or false */
PN potion_lobby_can(Potion *P, PN cl, PN self, PN method) {
- return potion_bind(P, self, method);
+ return potion_bind(P, self, method) ? PN_TRUE : PN_FALSE;
}
/**\memberof Lobby
View
2  core/potion.h
@@ -717,6 +717,8 @@ void potion_destroy(Potion *);
PN potion_error(Potion *, PN, long, long, PN);
void potion_fatal(char *);
void potion_allocation_error(void);
+PN potion_io_error(Potion *, PN);
+PN potion_type_error(Potion *, PN);
void potion_syntax_error(Potion *, const char *, ...)
__attribute__ ((format (printf, 2, 3)));
PNType potion_kind_of(PN);
View
314 lib/buffile.c
@@ -0,0 +1,314 @@
+/** \file lib/buffile.c
+ PNBufFile class for buffered stream FILE* IO
+
+ fgets, fopen, fscanf, fprintf, fread
+ \seealso http://stackoverflow.com/questions/1658476/c-fopen-vs-open
+
+ (c) 2013 perl11.org */
+#define __USE_XOPEN2K8
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+//#include <errno.h>
+#include "p2.h"
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#define HAVE_FMEMOPEN
+#endif
+
+struct PNBufFile {
+ PN_OBJECT_HEADER;
+ PN_SIZE siz;
+ FILE * file;
+ PN path;
+};
+typedef vPN(BufFile) pn_ffile;
+const int BufFileSize = sizeof(struct PNBufFile) - sizeof(struct PNData);
+
+/**\memberof PNBufFile
+ opens a buffered stream
+ \param path PNString
+ \param modestr PNString r,r+,w,w+,a,a+
+ \returns opened PNBufFile or PNError */
+PN potion_buffile_fopen(Potion *P, PN cl, PN ign, PN path, PN modestr) {
+ FILE *file;
+ struct PNBufFile *self;
+ if (!(file = fopen(PN_STR_PTR(path), PN_STR_PTR(modestr))))
+ return potion_io_error(P, PN_STR("open"));
+ self = (struct PNBufFile *)potion_data_alloc(P, sizeof(struct PNBufFile));
+ self->siz = BufFileSize;
+ self->file = file;
+ self->path = path;
+ return (PN)self;
+}
+/**\memberof Lobby
+ create a temporary file with fdopen for w+
+ The file shall be automatically deleted when all references to the file are closed.
+ \return a new PNBufFile */
+PN potion_buffile_tmpfile(Potion *P, PN cl, PN ign) {
+ struct PNBufFile *self;
+ self = (struct PNBufFile *)potion_data_alloc(P, sizeof(struct PNBufFile));
+ self->siz = BufFileSize;
+ self->file = tmpfile();
+ if (!self->file)
+ return potion_io_error(P, PN_STR("tmpfile"));
+ self->path = PN_NIL;
+ return (PN)self;
+}
+/**\memberof PNBufFile
+ \c fdopen associate a stream with the existing file descriptor, fd
+ \see potion_buffile_with_fd()
+ \param fd PN_NUM
+ \param modestr PNString r,r+,w,w+,a,a+
+ \returns PNBufFile or PNError */
+PN potion_buffile_fdopen(Potion *P, PN cl, pn_ffile self, PN fd, PN modestr) {
+ FILE *file;
+ if (!(file = fdopen(PN_INT(fd), PN_STR_PTR(modestr))))
+ return potion_io_error(P, PN_STR("fdopen"));
+ self->siz = BufFileSize;
+ self->file = file;
+ self->path = PN_NIL;
+ return (PN)self;
+}
+
+/**\memberof PNBufFile
+ \c freopen opens the file whose name is the string pointed to by path and associates the stream
+ pointed to by the stream argument with it. The original file (if it exists) is closed.
+ The primary use of the freopen() function is to change the file associated with
+ a standard text stream (stderr, stdin, or stdout).
+ \param path PNString
+ \param modestr PNString r,r+,w,w+,a,a+
+ \param stream PNBufFile
+ \returns PNBufFile or PNError */
+PN potion_buffile_freopen(Potion *P, PN cl, pn_ffile self, PN path, PN modestr, pn_ffile stream) {
+ FILE *file;
+ if ((PN_TYPE(stream) != PN_TUSER) ||
+ !(file = freopen(PN_STR_PTR(path), PN_STR_PTR(modestr), stream->file))) {
+ return potion_io_error(P, PN_STR("freopen"));
+ }
+ self->siz = BufFileSize;
+ self->file = file;
+ self->path = stream->path;
+ return (PN)self;
+}
+
+#ifdef HAVE_FMEMOPEN
+/**\memberof PNBytes
+ \c fmemopen opens a stream that permits the access specified by mode.
+ The stream allows I/O to be performed on the string or memory buffer
+ pointed to by buf.
+ \param buf PNBytes
+ \param modestr PNString r,r+,w,w+,a,a+
+ \see `man 3 fmemopen`
+ \returns PNBufFile or PNError */
+PN potion_buffile_fmemopen(Potion *P, PN cl, PN buf, PN modestr) {
+ FILE *file;
+ struct PNBufFile *self;
+ if (!(file = fmemopen(PN_STR_PTR(buf), PN_STR_LEN(buf), PN_STR_PTR(modestr))))
+ return potion_io_error(P, PN_STR("fmemopen"));
+ self = (struct PNBufFile *)potion_data_alloc(P, sizeof(struct PNBufFile));
+ self->siz = BufFileSize;
+ self->file = file;
+ self->path = PN_NIL;
+ return (PN)self;
+}
+#endif
+
+/**\memberof PNBufFile
+ \c flush and \c close a PNBufFile.
+ \return PNNumber (0 or EOF) */
+PN potion_buffile_fclose(Potion *P, PN cl, pn_ffile self) {
+ return PN_NUM(fclose(self->file));
+}
+/**\memberof PNBufFile
+ \c read the next character from a PNBufFile
+ \return PNNumber */
+PN potion_buffile_fgetc(Potion *P, PN cl, pn_ffile self) {
+ return PN_NUM(fgetc(self->file));
+}
+/**\memberof PNBufFile
+ read next line from PNBufFile, max 1024
+ \see potion_lobby_read() and potion_file_read()
+ \return PNBytes or PN_NIL */
+PN potion_buffile_fgets(Potion *P, PN cl, pn_ffile self) {
+ const int linemax = 1024;
+ char line[linemax];
+ if (fgets(line, linemax, self->file) != NULL)
+ return potion_byte_str(P, line);
+ return PN_NIL;
+}
+/**\memberof PNBufFile
+ \c read nitems of size from the stream into the PNBytes buf
+ \param buf PNBytes
+ \param size PNNumber
+ \param nitems PNNumber
+ \return PNNumber of read items or PNError */
+PN potion_buffile_fread(Potion *P, PN cl, pn_ffile self, PN buf, PN size, PN nitems) {
+ int r = fread(PN_STR_PTR(buf), PN_INT(size), PN_INT(nitems), self->file);
+ if (r < PN_INT(nitems))
+ return potion_io_error(P, PN_STR("fread"));
+ return PN_NUM(r);
+}
+/**\memberof PNBufFile
+ \c write nitems of size starting at the pointer pointing to buf to the stream.
+ \param buf PNBytes or PNString
+ \param size PNNumber or if PN_NIL the length of buf
+ \param nitems PNNumber, default 1
+ \return PNNumber of written items or PNError */
+PN potion_buffile_fwrite(Potion *P, PN cl, pn_ffile self, PN buf, PN size, PN nitems) {
+ if (!size && (!nitems || PN_INT(nitems) == 1)) {
+ size = potion_send(buf, PN_STR("length"));
+ nitems = PN_NUM(1);
+ }
+ switch (PN_TYPE(buf)) {
+ case PN_TSTRING:
+ case PN_TBYTES: break;
+ case PN_NIL: return PN_NIL;
+ default: return potion_type_error(P, buf);
+ }
+ int r = fwrite(PN_STR_PTR(buf), PN_INT(size), PN_INT(nitems), self->file);
+ if (r < PN_INT(nitems))
+ return potion_io_error(P, PN_STR("fwrite"));
+ return PN_NUM(r);
+}
+/**\memberof PNBufFile
+ \c write the byte (0-255) to a PNBufFile
+ \param byte PNNumber
+ \return PNNumber */
+PN potion_buffile_fputc(Potion *P, PN cl, pn_ffile self, PN byte) {
+ return PN_NUM(fputc(PN_INT(byte), self->file));
+}
+/**\memberof PNBufFile
+ \c write line to PNBufFile
+ \param str PNString or PNBytes
+ \return PNNumber or PNError */
+PN potion_buffile_fputs(Potion *P, PN cl, pn_ffile self, PN str) {
+ int r;
+ if (!(r=fputs(PN_STR_PTR(str), self->file)))
+ return potion_io_error(P, PN_STR("fputs"));
+ return PN_NUM(r);
+}
+/**\memberof PNBufFile
+ \c "fflush"
+ \return true or PNError */
+PN potion_buffile_fflush(Potion *P, PN cl, pn_ffile self) {
+ if (fflush(self->file))
+ return potion_io_error(P, PN_STR("fflush"));
+ return PN_TRUE;
+}
+/**\memberof PNBufFile
+ \c "fseek" set the file-position indicator for the stream.
+ \param offset PNNumber
+ \param whence PNNumber
+ \return true or PNError */
+PN potion_buffile_fseek(Potion *P, PN cl, pn_ffile self, PN offset, PN whence) {
+ if (fseek(self->file, PN_INT(offset), PN_INT(whence)))
+ return potion_io_error(P, PN_STR("fseek"));
+ return PN_TRUE;
+}
+/**\memberof PNBufFile
+ \c "ftell" returns the file-position indicator for the stream measured in bytes from the
+ beginning of the file.
+ \return PNNumber */
+PN potion_buffile_ftell(Potion *P, PN cl, pn_ffile self) {
+ long r = ftell(self->file);
+ if (r == -1)
+ return potion_io_error(P, PN_STR("ftell"));
+ return PN_NUM(r);
+}
+/**\memberof PNBufFile
+ \c "feof" tests the end-of-file indicator for the stream.
+ \return true or false */
+PN potion_buffile_feof(Potion *P, PN cl, pn_ffile self) {
+ int r = feof(self->file);
+ return r ? PN_TRUE : PN_FALSE;
+}
+/**\memberof PNBufFile
+ \c "fileno" \returns its integer file descriptor. */
+PN potion_buffile_fileno(Potion *P, PN cl, pn_ffile self) {
+ return PN_NUM(fileno(self->file));
+}
+/**\memberof PNBufFile
+ \c "unlink" the PNBufFile. close it if open.
+ \return true or nil */
+PN potion_buffile_unlink(Potion *P, PN cl, pn_ffile self) {
+ if (fileno(self->file) != -1) fclose(self->file);
+ if (!self->path || unlink(PN_STR_PTR(self->path))) {
+ return potion_io_error(P, PN_STR("unlink"));
+ }
+ return PN_TRUE;
+}
+/**\memberof PNBufFile
+ acquire for a thread ownership of a PNBufFile object */
+PN potion_buffile_flockfile(Potion *P, PN cl, pn_ffile self) {
+ flockfile(self->file); return PN_TRUE;
+}
+/**\memberof PNBufFile
+ non-blocking version of \see potion_buffile_flockfile().
+ \returns 0 for success */
+PN potion_buffile_ftrylockfile(Potion *P, PN cl, pn_ffile self) {
+ return PN_NUM(ftrylockfile(self->file));
+}
+/**\memberof PNBufFile
+ relinquish the ownership granted to the thread of a PNBufFile object */
+PN potion_buffile_funlockfile(Potion *P, PN cl, pn_ffile self) {
+ funlockfile(self->file); return PN_TRUE;
+}
+/**\memberof PNBufFile
+ \c "fprintf" to file.
+ \param obj any
+ \return PN_NIL */
+#if 0
+PN potion_buffile_fprintf(Potion *P, PN cl, pn_ffile self, PN fmt, ...) {
+ return fprintf(self->file, potion_send(obj, PN_string));
+}
+#endif
+/**\memberof PNBufFile
+ \c "string" method. some internal descr */
+PN potion_buffile_string(Potion *P, PN cl, pn_ffile self) {
+ int fd = fileno(self->file), rv;
+ char *buf;
+ PN str;
+ if (self->path != PN_NIL && fd != -1) {
+ rv = asprintf(&buf, "<buffile %s fd: %d>", PN_STR_PTR(self->path), fd);
+ } else if (fd != -1) {
+ rv = asprintf(&buf, "<buffile %p fd: %d>", self->file, fd);
+ } else {
+ rv = asprintf(&buf, "<closed buffile %p>", self->file);
+ }
+ if (rv == -1) potion_allocation_error();
+ str = potion_str(P, buf);
+ free(buf);
+ return str;
+}
+
+void Potion_Init_buffile(Potion *P) {
+ PN ffile_vt = potion_type_new2(P, PN_TUSER, PN_VTABLE(PN_TFILE), PN_STR("BufFile"));
+ potion_type_constructor_is(ffile_vt, PN_FUNC(potion_buffile_fopen, "path=S,mode=S"));
+ //potion_class_method(ffile_vt, "fd", potion_buffile_fdopen, "fd=N,mode=S");
+ potion_method(P->lobby, "fopen", potion_buffile_fopen, "ign=o,path=S,mode=S");
+ potion_method(ffile_vt, "fdopen", potion_buffile_fdopen, "fd=N,mode=S");
+ potion_method(ffile_vt, "freopen", potion_buffile_freopen, "path=S,mode=S,buffile=o");
+#ifdef HAVE_FMEMOPEN
+ potion_method(PN_VTABLE(PN_TBYTES), "fmemopen", potion_buffile_fmemopen, "mode=S");
+#endif
+ potion_method(ffile_vt, "close", potion_buffile_fclose, 0);
+ potion_method(ffile_vt, "fread", potion_buffile_fread, "buf=S,size=N,n:=1");
+ potion_method(ffile_vt, "write", potion_buffile_fwrite, "buf=S|size=N,n:=1");
+ //potion_method(ffile_vt, "fprintf", potion_buffile_fprintf, "fmt=S|...");
+ potion_method(ffile_vt, "fgetc", potion_buffile_fgetc, 0);
+ potion_method(ffile_vt, "fgets", potion_buffile_fgets, 0);
+ potion_method(ffile_vt, "fputc", potion_buffile_fputc, "byte=N");
+ potion_method(ffile_vt, "fputs", potion_buffile_fputs, "str=S");
+ potion_method(ffile_vt, "fflush", potion_buffile_fflush, 0);
+ potion_method(ffile_vt, "fseek", potion_buffile_fseek, "offset=N, whence=N");
+ potion_method(ffile_vt, "ftell", potion_buffile_ftell, 0);
+ potion_method(ffile_vt, "feof", potion_buffile_feof, 0);
+ potion_method(ffile_vt, "fileno", potion_buffile_fileno, 0);
+ potion_method(ffile_vt, "flockfile", potion_buffile_flockfile, 0);
+ potion_method(ffile_vt, "ftrylockfile", potion_buffile_ftrylockfile, 0);
+ potion_method(ffile_vt, "funlockfile", potion_buffile_funlockfile, 0);
+ potion_method(ffile_vt, "unlink", potion_buffile_unlink, 0);
+ potion_method(ffile_vt, "string", potion_buffile_string, 0);
+ potion_method(P->lobby, "tmpfile", potion_buffile_tmpfile, 0);
+}
View
16 lib/pcre/Makefile
@@ -0,0 +1,16 @@
+include ../../config.inc
+INCS += -I../../core -I../../3rd/pcre
+LIBS += -L.. -lpotion -L../../3rd/pcre -lpcre
+SRC =
+
+all: pcre${LOADEXT}
+
+%${LOADEXT}: %.c
+ @if [ -f ../../libpotion.a ]; then mv ../../libpotion.a ../../libpotion.a.tmp; fi
+ @$(CC) $(CFLAGS) -o $@ $(INCS) $(LDDLLFLAGS) $(SRC) $< $(LIBS)
+ @if [ -f ../../libpotion.a.tmp ]; then mv ../../libpotion.a.tmp ../../libpotion.a; fi
+
+test:
+
+clean:
+ @rm -f ../pcre${LOADEXT} pcre${LOADEXT} *.o
View
73 lib/pcre/pcre.c
@@ -0,0 +1,73 @@
+/** \file lib/pcre.c
+ pcre bindings
+
+ "test" match("(?:i)(abc*)|(a)") => PNMatch (scalar context: bool, list context: results)
+ "test" replace("(?:g)(abc*)|(a)", "\2") => PNString
+
+ (c) 2013 perl.org */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "p2.h"
+
+#include "pcre.h"
+typedef struct { PNType vt; PNUniq uniq; PN_SIZE len; PN_SIZE siz; pcre *ptr; } PNMatch;
+//PN_FLEX(PNMatch, struct real_pcre);
+//PN_FLEX(PNMatchExtra, pcre_extra);
+//PN_FLEX(PNMatchCB, pcre_callout_block);
+
+// return true/false, utf8
+static PN potion_string_boolmatch(Potion *P, PN cl, PN self, PN str) {
+}
+// no-utf8
+static PN potion_bytes_boolmatch(Potion *P, PN cl, PN self, PN str) {
+}
+// return list of matches
+static PN potion_string_listmatch(Potion *P, PN cl, PN self, PN str) {
+}
+static PN potion_bytes_listmatch(Potion *P, PN cl, PN self, PN str) {
+}
+// match against pre-compiled regex (result of compile method)
+static PN potion_string_qr(Potion *P, PN cl, PN self, PN qr) {
+}
+static PN potion_bytes_qr(Potion *P, PN cl, PN self, PN qr) {
+}
+//\returns PNMatchExtra
+static PN potion_string_study(Potion *P, PN cl, PN self) {
+}
+//\return copy of string
+static PN potion_string_replace(Potion *P, PN cl, PN self, PN str, PN with) {
+}
+//\return destructive replace
+static PN potion_bytes_replace(Potion *P, PN cl, PN self, PN str, PN with) {
+}
+//\returns PNMatch (qr)
+static PN potion_string_compile(Potion *P, PN cl, PN self) {
+}
+//\returns i-th match
+static PN potion_match_at(Potion *P, PN cl, PN self) {
+}
+//\returns named match
+static PN potion_match_result(Potion *P, PN cl, PN self, PN str) {
+}
+
+void potion_pcre_init(Potion *P) {
+ PN str_vt = PN_VTABLE(PN_TSTRING);
+ PN byt_vt = PN_VTABLE(PN_TBYTES);
+ //PN mat_vt = PN_VTABLE(PNMatch);
+ PN mat_vt = potion_type_new2(P, PN_TUSER, PN_VTABLE(PN_TLICK), potion_str(P, "Match"));
+ //PN mat_vt = PN_VTABLE(PNMatch);
+ potion_method(str_vt, "match", potion_string_boolmatch, "str=S"); //match utf8 string against string
+ potion_method(byt_vt, "match", potion_bytes_boolmatch, "str=S"); //on no-utf8 buffer
+ potion_method(str_vt, "listmatch", potion_string_listmatch, "str=S"); //return results as list
+ potion_method(byt_vt, "listmatch", potion_bytes_listmatch, "str=S");
+ potion_method(str_vt, "qr", potion_string_qr, "qr=o"); // match against pre-compiled regex
+ potion_method(byt_vt, "qr", potion_bytes_qr, "qr=o");
+ potion_method(str_vt, "study", potion_string_study, 0); //< \returns PNMatchExtra
+
+ potion_method(str_vt, "replace", potion_string_replace, "str=S,with=S"); //copy, on utf8 string
+ potion_method(byt_vt, "replace", potion_bytes_replace, "str=S,with=S"); //destructive, on no-utf8 buffer
+ potion_method(str_vt, "compile", potion_string_compile, 0); //< \returns PNMatch (qr)
+ potion_type_call_is(mat_vt, PN_FUNC(potion_match_at, 0)); //< \returns i-th match
+ potion_method(mat_vt, "result", potion_match_result, "str=S"); //named result
+}
View
2  lib/readline/Makefile
@@ -1,6 +1,6 @@
include ../../config.inc
INCS += -I../../core
-LIBS += -L../potion -lpotion
+LIBS += -L.. -lpotion
SRC = linenoise.c
ifeq ($(WIN32),1)
SRC += win32fixes.c
View
7 test/misc/buffile.pn
@@ -0,0 +1,7 @@
+load "buffile"
+#f = tmpfile
+f = fopen("tmpfile.tmp", "w")
+buf = "xxx"
+x = f write(buf,nil,1)
+y = f unlink
+(x, y) #=> (1, true)
Please sign in to comment.
Something went wrong with that request. Please try again.