potion  0.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
file.c
Go to the documentation of this file.
1 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <sys/stat.h>
18 #include <errno.h>
19 #include <assert.h>
20 #include "potion.h"
21 #include "internal.h"
22 #include "table.h"
23 
24 #ifdef __APPLE__
25 # include <crt_externs.h>
26 # undef environ
27 # define environ (*_NSGetEnviron())
28 #else
29  extern char **environ;
30 #endif
31 
32 typedef struct PNFile * volatile pn_file;
33 
39 PN potion_file_new(Potion *P, PN cl, PN self, PN path, PN modestr) {
40  int fd;
41  mode_t mode;
42  if (strcmp(PN_STR_PTR(modestr), "r") == 0) {
43  mode = O_RDONLY;
44  } else if (strcmp(PN_STR_PTR(modestr), "r+") == 0) {
45  mode = O_RDWR;
46  } else if (strcmp(PN_STR_PTR(modestr), "w") == 0) {
47  mode = O_WRONLY | O_TRUNC | O_CREAT;
48  } else if (strcmp(PN_STR_PTR(modestr), "w+") == 0) {
49  mode = O_RDWR | O_TRUNC | O_CREAT;
50  } else if (strcmp(PN_STR_PTR(modestr), "a") == 0) {
51  mode = O_WRONLY | O_CREAT | O_APPEND;
52  } else if (strcmp(PN_STR_PTR(modestr), "a+") == 0) {
53  mode = O_RDWR | O_CREAT | O_APPEND;
54  } else {
55  // invalid mode
56  return PN_NIL;
57  }
58  if ((fd = open(PN_STR_PTR(path), mode, 0755)) == -1)
59  return potion_io_error(P, "open");
60  ((struct PNFile *)self)->fd = fd;
61  ((struct PNFile *)self)->path = path;
62  ((struct PNFile *)self)->mode = mode;
63  return self;
64 }
65 
71  struct PNFile *file = (struct PNFile *)potion_object_new(P, PN_NIL, PN_VTABLE(PN_TFILE));
72  file->fd = PN_INT(fd);
73  file->path = PN_NIL;
74 #ifdef F_GETFL
75  file->mode = fcntl(file->fd, F_GETFL) | O_ACCMODE;
76 #else
77  struct stat st;
78  if (fstat(file->fd, &st) == -1) perror("fstat");
79  file->mode = st.st_mode;
80 #endif
81  return (PN)file;
82 }
83 
87 PN potion_file_close(Potion *P, PN cl, pn_file self) {
88  int retval;
89  while (retval = close(self->fd), retval == -1 && errno == EINTR) ;
90  self->fd = -1;
91  return PN_NIL;
92 }
93 
98 PN potion_file_read(Potion *P, PN cl, pn_file self, PN n) {
99  n = PN_INT(n);
100  char buf[n];
101  int r = read(self->fd, buf, n);
102  if (r == -1) {
103  return potion_io_error(P, "read");
104  //perror("read");
105  // TODO: error
106  //return PN_NUM(-1);
107  } else if (r == 0) {
108  return PN_NIL;
109  }
110  return potion_byte_str2(P, buf, r);
111 }
112 
117 PN potion_file_write(Potion *P, PN cl, pn_file self, PN obj) {
118  long len = 0;
119  char *ptr = NULL;
120  //TODO: maybe extract ptr+len to seperate function
121  if (!PN_IS_PTR(obj)) {
122  if (!obj) return PN_NIL; //silent
123  else if (PN_IS_INT(obj)) {
124  long tmp = PN_NUM(obj); len = sizeof(tmp); ptr = (char *)&tmp;
125  }
126  else if (PN_IS_BOOL(obj)) {
127  char tmp = (obj == PN_TRUE) ? 1 : 0; len = 1; ptr = (char *)&tmp;
128  }
129  else {
130  assert(0 && "Invalid primitive type");
131  }
132  } else {
133  switch (PN_TYPE(obj)) {
134  case PN_TSTRING: len = PN_STR_LEN(obj); ptr = PN_STR_PTR(obj); break;
135  case PN_TBYTES: len = potion_send(obj, PN_STR("length")); ptr = PN_STR_PTR(obj); break;
136  case PN_TNUMBER: {
137  double tmp = PN_DBL(obj); len = sizeof(tmp); ptr = (char *)&tmp;
138  break;
139  }
140  default: return potion_type_error(P, obj);
141  }
142  }
143  int r = write(self->fd, ptr, len);
144  if (r == -1)
145  return potion_io_error(P, "write");
146  return PN_NUM(r);
147 }
148 
154 PN potion_file_print(Potion *P, PN cl, pn_file self, PN obj) {
155  PN r = potion_file_write(P, cl, self, potion_send(obj, PN_string));
156  return PN_IS_INT(r) ? PN_STR0 : r;
157 }
158 
161 PN potion_file_string(Potion *P, PN cl, pn_file self) {
162  int fd = self->fd, rv;
163  char *buf;
164  PN str;
165  if (self->path != PN_NIL && fd != -1) {
166  rv = asprintf(&buf, "<file %s fd: %d>", PN_STR_PTR(self->path), fd);
167  } else if (fd != -1) {
168  rv = asprintf(&buf, "<file fd: %d>", fd);
169  } else {
170  rv = asprintf(&buf, "<closed file>");
171  }
172  if (rv == -1) potion_allocation_error();
173  str = potion_str(P, buf);
174  free(buf);
175  return str;
176 }
177 
181 PN potion_lobby_read(Potion *P, PN cl, PN self) {
182  char line[1024];
183  if (fgets(line, 1024, stdin) != NULL)
184  return potion_str(P, line);
185  return PN_NIL;
186 }
187 
190  PN file_vt = PN_VTABLE(PN_TFILE);
191  char **env = environ, *key;
192  PN pe = potion_table_empty(P);
193  while (*env != NULL) {
194  for (key = *env; *key != '='; key++);
195  potion_table_put(P, PN_NIL, pe, PN_STRN(*env, key - *env),
196  potion_str(P, key + 1));
197  env++;
198  }
199  potion_send(P->lobby, PN_def, PN_STRN("Env", 3), pe);
200  potion_method(P->lobby, "read", potion_lobby_read, 0);
201 
202  potion_type_constructor_is(file_vt, PN_FUNC(potion_file_new, "path=S,mode=S"));
203  potion_class_method(file_vt, "fd", potion_file_with_fd, "fd=N");
204  potion_method(file_vt, "string", potion_file_string, 0);
205  potion_method(file_vt, "close", potion_file_close, 0);
206  potion_method(file_vt, "read", potion_file_read, "n=N");
207  potion_method(file_vt, "write", potion_file_write, "str=S");
208  potion_method(file_vt, "print", potion_file_print, "obj=o");
209 }
PN potion_file_write(Potion *P, PN cl, pn_file self, PN obj)
Definition: file.c:117
PN potion_str(Potion *, const char *)
Definition: string.c:33
PN potion_file_string(Potion *P, PN cl, pn_file self)
Definition: file.c:161
PN potion_lobby_read(Potion *P, PN cl, PN self)
Definition: file.c:181
#define PN_TSTRING
Definition: potion.h:112
PN potion_file_read(Potion *P, PN cl, pn_file self, PN n)
Definition: file.c:98
PN potion_table_put(Potion *P, PN cl, PN self, PN key, PN value)
Definition: table.c:98
#define potion_method(RCV, MSG, FN, SIG)
Definition: potion.h:780
PN potion_file_print(Potion *P, PN cl, pn_file self, PN obj)
Definition: file.c:154
#define PN_TFILE
Definition: potion.h:117
PN potion_byte_str2(Potion *, const char *, size_t len)
Definition: string.c:335
#define PN_STR_LEN(x)
Definition: potion.h:214
a file is wrapper around a file descriptor, non-volatile but mutable.
Definition: potion.h:361
PN PN_string
Definition: internal.c:14
void potion_file_init(Potion *P)
set Env global
Definition: file.c:189
#define PN_TBYTES
Definition: potion.h:121
#define PN_STR(x)
Definition: potion.h:210
#define PN_INT(x)
Definition: potion.h:205
#define PN_NUM(i)
Definition: potion.h:204
PN potion_file_new(Potion *P, PN cl, PN self, PN path, PN modestr)
Definition: file.c:39
PN lobby
root namespace
Definition: potion.h:648
PN potion_table_empty(Potion *P)
Definition: table.c:42
PN potion_file_with_fd(Potion *P, PN cl, PN self, PN fd)
Definition: file.c:70
PN potion_io_error(Potion *P, const char *msg)
Definition: internal.c:255
#define PN_DBL(num)
Definition: potion.h:206
#define PN_IS_BOOL(v)
Definition: potion.h:161
PN potion_type_error(Potion *P, PN obj)
Definition: internal.c:269
struct PNFile *volatile pn_file
Definition: file.c:32
#define PN_TRUE
Definition: potion.h:142
non-API internal parts
#define PN_IS_PTR(v)
Definition: potion.h:159
PN potion_file_close(Potion *P, PN cl, pn_file self)
Definition: file.c:87
PN path
Definition: potion.h:364
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:644
The potion API.
PN PN_def
Definition: internal.c:14
#define PN_TYPE(x)
Definition: potion.h:133
#define PN_IS_INT(v)
Definition: potion.h:162
the central table type, based on core/khash.h
mode_t mode
Definition: potion.h:365
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
Definition: potion.h:772
#define PN_STRN(x, l)
Definition: potion.h:211
char ** environ
void potion_allocation_error(void)
Definition: internal.c:301
volatile _PN PN
Definition: potion.h:81
PN PN_STR0
Definition: internal.c:18
#define PN_NIL
Definition: potion.h:139
#define PN_TNUMBER
Definition: potion.h:108
#define PN_FUNC(f, s)
Definition: potion.h:219
void potion_type_constructor_is(PN vt, PN cl)
set default constructor
Definition: objmodel.c:245
#define potion_class_method(RCV, MSG, FN, SIG)
Definition: potion.h:782
int fd
Definition: potion.h:363
#define PN_STR_PTR(x)
Definition: potion.h:213
#define PN_VTABLE(t)
Definition: potion.h:136
PN potion_object_new(Potion *P, PN cl, PN self)
Definition: objmodel.c:516