p2  0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
load.c
Go to the documentation of this file.
1 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <dlfcn.h>
11 #include <sys/stat.h>
12 #include "p2.h"
13 #include "internal.h"
14 #include "table.h"
15 
16 static PN potion_load_code(Potion *P, const char *filename) {
17  PN buf, code;
18  struct stat stats;
19  int fd = -1;
20  PN result = PN_NIL;
21  if (stat(filename, &stats) == -1) {
22  fprintf(stderr, "** %s does not exist.", filename);
23  return PN_NIL;
24  }
25  fd = open(filename, O_RDONLY | O_BINARY);
26  if (fd == -1) {
27  fprintf(stderr, "** could not open %s. check permissions.", filename);
28  return PN_NIL;
29  }
30  buf = potion_bytes(P, stats.st_size);
31  if (read(fd, PN_STR_PTR(buf), stats.st_size) == stats.st_size) {
32  PN_STR_PTR(buf)[stats.st_size] = '\0';
33  code = potion_source_load(P, PN_NIL, buf);
34  if (!PN_IS_PROTO(code)) {
35  result = potion_run(P, potion_send(
36  potion_parse(P, buf, (char *)filename),
37  PN_compile, potion_str(P, filename), PN_NIL),
38  POTION_JIT);
39  }
40  } else {
41  fprintf(stderr, "** could not read entire file: %s.", filename);
42  }
43  close(fd);
44  return result;
45 }
46 
47 static char *potion_initializer_name(Potion *P, const char *filename, PN_SIZE len) {
48  PN_SIZE ext_name_len = 0;
49  char *allocated_str, *ext_name, *func_name;
50  while (*(filename + ++ext_name_len) != '.' && ext_name_len <= len);
51  allocated_str = ext_name = malloc(ext_name_len + 1);
52  if (allocated_str == NULL) potion_allocation_error();
53  strncpy(ext_name, filename, ext_name_len);
54  ext_name[ext_name_len] = '\0';
55  ext_name += ext_name_len;
56  while (*--ext_name != '/' && ext_name >= allocated_str);
57  ext_name++;
58  if (asprintf(&func_name, "Potion_Init_%s", ext_name) == -1)
60  free(allocated_str);
61  return func_name;
62 }
63 
64 static PN potion_load_dylib(Potion *P, const char *filename) {
65  void *handle = dlopen(filename, RTLD_LAZY);
66  void (*func)(Potion *);
67  char *err, *init_func_name;
68  if (handle == NULL) {
69  // TODO: error
70  fprintf(stderr, "** error loading %s: %s\n", filename, dlerror());
71  return PN_NIL;
72  }
73  init_func_name = potion_initializer_name(P, filename, strlen(filename));
74  func = (void (*)(Potion *))dlsym(handle, init_func_name);
75  err = (char *)dlerror();
76  free(init_func_name);
77  if (err != NULL) {
78  fprintf(stderr, "** error loading %s in %s: %s\n", init_func_name, filename, err);
79  dlclose(handle);
80  return PN_NIL;
81  }
82  func(P);
83  return PN_TRUE;
84 }
85 
87 static const char *pn_loader_extensions[] = {
88 #ifndef P2
89  ".pnb"
90  , ".pn"
91 #else
92  ".plc"
93  , ".pl"
94  , ".pmc"
95  , ".pm"
96 #endif
98 };
99 
100 static const char *find_extension(char *str) {
101  int i;
102  PN_SIZE str_len = strlen(str);
103  struct stat st;
104  for (i = 0;
105  i < sizeof(pn_loader_extensions) / sizeof(void *);
106  i++) {
107  PN_SIZE len = strlen(pn_loader_extensions[i]);
108  char buf[str_len + len + 1];
109  strncpy(buf, str, str_len);
110  strncpy(buf + str_len, pn_loader_extensions[i], len);
111  buf[str_len + len] = '\0';
112  if (stat(buf, &st) == 0 && S_ISREG(st.st_mode))
113  return pn_loader_extensions[i];
114  }
115  return NULL;
116 }
117 
118 char *potion_find_file(Potion *P, char *str, PN_SIZE str_len) {
119  char *r = NULL;
120  struct stat st;
121  if (!str_len) str_len = strlen(str);
122  PN_TUPLE_EACH(pn_loader_path, i, prefix, {
123  PN_SIZE prefix_len = PN_STR_LEN(prefix);
124  char dirname[prefix_len + 1 + str_len + 1];
125  char *str_pos = dirname + prefix_len + 1;
126  char *dot;
127  const char *ext;
128  memcpy(str_pos, str, str_len);
129  dot = memchr(str, '.', str_len);
130  if (dot == NULL)
131  dirname[sizeof(dirname) - 1] = '\0';
132  else
133  *dot = '\0';
134  memcpy(dirname, PN_STR_PTR(prefix), prefix_len);
135  dirname[prefix_len] = '/';
136  if (stat(dirname, &st) == 0 && S_ISREG(st.st_mode)) {
137  if (asprintf(&r, "%s", dirname) == -1) potion_allocation_error();
138  break;
139  } else if ((ext = find_extension(dirname)) != NULL) {
140  if (asprintf(&r, "%s%s", dirname, ext) == -1) potion_allocation_error();
141  break;
142  } else {
143  char *file;
144  if ((file = strrchr(str, '/')) == NULL)
145  file = str;
146  else
147  file++;
148  if (asprintf(&r, "%s/%s", dirname, file) == -1) potion_allocation_error();
149  if (stat(r, &st) != 0 || !S_ISREG(st.st_mode)) {
150  int r_len = prefix_len + 1 + str_len * 2 + 1;
151  if ((ext = find_extension(r)) == NULL) { free(r); r = NULL; continue; }
152  r = realloc(r, r_len + strlen(ext));
153  if (r == NULL) potion_allocation_error();
154  strcpy(r + r_len, ext);
155  }
156  break;
157  }
158  });
159  return r;
160 }
161 
162 #ifndef P2
163 PN potion_load(Potion *P, PN cl, PN self, PN file) {
164  if (!file && PN_IS_STR(self))
165  file = self;
166  char *filename = potion_find_file(P, PN_STR_PTR(file), PN_STR_LEN(file));
167  char *file_ext;
168  PN result = PN_NIL;
169  if (filename == NULL) {
170  fprintf(stderr, "** can't find %s\n", PN_STR_PTR(file));
171  return PN_NIL;
172  }
173  file_ext = filename + strlen(filename);
174  while (*--file_ext != '.' && file_ext >= filename);
175  if (file_ext++ != filename) {
176  if (strcmp(file_ext, "pn") == 0)
177  result = potion_load_code(P, filename);
178  else if (strcmp(file_ext, "pnb") == 0)
179  result = potion_load_code(P, filename);
180  else if (strcmp(file_ext, POTION_LOADEXT+1) == 0)
181  result = potion_load_dylib(P, filename);
182  else
183  fprintf(stderr, "** unrecognized file extension: %s\n", file_ext);
184  } else {
185  fprintf(stderr, "** no file extension: %s\n", filename);
186  }
187  free(filename);
188  return result;
189 }
190 
191 #else
192 
193 PN p2_load(Potion *P, PN cl, PN self, PN file) {
194  if (!file && PN_IS_STR(self))
195  file = self;
196  char *filename = potion_find_file(P, PN_STR_PTR(file), PN_STR_LEN(file)), *file_ext;
197  PN result = PN_NIL;
198  if (filename == NULL) {
199  fprintf(stderr, "** can't find %s\n", PN_STR_PTR(file));
200  return PN_NIL;
201  }
202  file_ext = filename + strlen(filename);
203  while (*--file_ext != '.' && file_ext >= filename);
204  if (file_ext++ != filename) {
205  if (strcmp(file_ext, "pl") == 0)
206  result = p2_load_code(P, filename);
207  else if (strcmp(file_ext, "plc") == 0)
208  result = p2_load_code(P, filename);
209  else if (strcmp(file_ext, POTION_LOADEXT+1) == 0)
210  result = potion_load_dylib(P, filename);
211  else
212  fprintf(stderr, "** unrecognized file extension: %s\n", file_ext);
213  } else {
214  fprintf(stderr, "** no file extension: %s\n", filename);
215  }
216  free(filename);
217  return result;
218 }
219 #endif
220 
221 void potion_loader_add(Potion *P, PN path) {
222  PN_PUSH(pn_loader_path, path);
223 }
224 
227  // relocatable path - relative to exe in argv[0]
228  //PN arg0 = potion_send(potion_str(P, "$^X")); // but too early for argv[0]
229  //if (arg0) PN_PUSH(pn_loader_path, potion_strcat(P, basename(PN_STR_PTR(arg0)), "../lib/potion"));
230 #ifdef P2
231  PN_PUSH(pn_loader_path, potion_str(P, "lib/p2"));
233 #endif
234  PN_PUSH(pn_loader_path, potion_str(P, "lib/potion"));
235  PN_PUSH(pn_loader_path, potion_str(P, POTION_PREFIX"/lib/potion"));
237 
238 #ifdef P2
239 #define LOADER_PATH "@INC"
240 #else
241 #define LOADER_PATH "LOADER_PATH"
242 #endif
244  potion_method(P->lobby, "load", potion_load, "file=S");
245 }
PN PN_compile
Definition: internal.c:14
#define PN_IS_STR(v)
Definition: potion.h:175
PN potion_bytes(Potion *, size_t)
Definition: string.c:342
PN potion_str(Potion *, const char *)
Definition: string.c:33
#define LOADER_PATH
static char * potion_initializer_name(Potion *P, const char *filename, PN_SIZE len)
Definition: load.c:47
#define potion_method(RCV, MSG, FN, SIG)
Definition: potion.h:789
#define PN_PUSH(T, X)
Definition: potion.h:272
#define PN_STR_LEN(x)
Definition: potion.h:223
PN potion_source_load(Potion *P, PN cl, PN buf)
Definition: compile.c:1287
#define POTION_PREFIX
Definition: config.h:12
#define POTION_JIT
Definition: config.h:17
unsigned int PN_SIZE
Definition: potion.h:79
PN potion_load(Potion *P, PN cl, PN self, PN file)
Definition: load.c:163
PN lobby
root namespace
Definition: potion.h:657
PN p2_load(Potion *, PN, PN, PN)
PN potion_run(Potion *P, PN code, int jit)
Definition: compile.c:1399
void potion_define_global(Potion *P, PN name, PN val)
Definition: objmodel.c:628
PN potion_parse(Potion *, PN, char *)
static PN potion_load_dylib(Potion *P, const char *filename)
Definition: load.c:64
static PN potion_load_code(Potion *P, const char *filename)
Definition: load.c:16
#define PN_TRUE
Definition: potion.h:142
#define POTION_LOADEXT
Definition: config.h:15
non-API internal parts
#define PN_IS_PROTO(v)
Definition: potion.h:178
static const char * find_extension(char *str)
Definition: load.c:100
static const char * pn_loader_extensions[]
Definition: load.c:87
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:653
void potion_loader_init(Potion *P)
Definition: load.c:225
The p2 API.
the central table type, based on core/khash.h
static PN pn_loader_path
Definition: load.c:86
#define O_BINARY
Definition: internal.h:128
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
Definition: potion.h:781
void potion_allocation_error(void)
Definition: internal.c:305
volatile _PN PN
Definition: potion.h:81
#define PN_NIL
Definition: potion.h:139
void potion_loader_add(Potion *P, PN path)
Definition: load.c:221
#define PN_TUPLE_EACH(T, I, V, B)
Definition: potion.h:288
#define PN_STR_PTR(x)
Definition: potion.h:222
#define PN_TUP0()
Definition: potion.h:270
char * potion_find_file(Potion *P, char *str, PN_SIZE str_len)
Definition: load.c:118