/
libdir.c
194 lines (174 loc) · 6.09 KB
/
libdir.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "m_pd.h"
#include "s_stuff.h"
#include "g_canvas.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
/* this object requires Pd 0.40.3 or later */
/* WARNING: KLUDGE! */
/*
* this struct is not publically defined (its in g_canvas.c) so I need to
* include this here. Its from Pd 0.47-0. */
struct _canvasenvironment
{
t_symbol *ce_dir; /* directory patch lives in */
int ce_argc; /* number of "$" arguments */
t_atom *ce_argv; /* array of "$" arguments */
int ce_dollarzero; /* value of "$0" */
t_namelist *ce_path; /* search path */
};
static char *version =
#ifdef VERSION
VERSION
#else
"unknown"
#endif
;
/* This loader opens a directory with a -meta.pd file as a library. In the
* long run, the idea is that one folder will have all of objects files, all
* of the related *-help.pd files, a file with meta data for the help system,
* etc. Then to install the lib, it would just be dropped into extra, or
* anywhere in the global classpath.
*
* Ultimately, the meta file will be read for meta data, specifically for
* the auto-generated Help system, but for other things too. Right now,
* its just used as a marker that a directory is meant to be a library.
* Plus its much easier to implement it this way, I can use
* open_via_path() instead of writing a new function. The grand plan is
* to have one directory hold the objects, help files, manuals,
* etc. making it a self-contained library. <hans@at.or.at>
*/
/*
* TODO
* - get 'declare' messages from the meta-file, and send them to the current canvas
*/
static void libdir_get_fullname(char*dest, size_t size, const char*classname) {
snprintf(dest, size-1, "%s/%s-meta", classname, classname);
dest[size-1]=0;
}
#if PD_MAJOR_VERSION>0 || PD_MINOR_VERSION>47
/* gone from the headers, but still present for binary compat */
extern t_namelist *sys_searchpath;
#endif
static int libdir_add_to_globalpath(const char*path) {
int major, minor, bugfix;
sys_getversion(&major, &minor, &bugfix);
if((major==0 && minor < 48)) {
sys_searchpath = namelist_append(sys_searchpath, path, 0);
} else {
const char *inptr = path;
char encoded[MAXPDSTRING];
char *outptr = encoded;
t_atom ap[2];
*outptr++='+';
while(inptr && ((outptr+2) < (encoded+MAXPDSTRING))) {
*outptr++ = *inptr++;
if ('+'==inptr[-1])
*outptr++='+';
}
*outptr=0;
SETSYMBOL(ap+0, gensym(encoded));
SETFLOAT(ap+1, 0.f);
pd_typedmess(gensym("pd")->s_thing, gensym("add-to-path"), 2, ap);
}
return 1;
}
static int libdir_add_to_path(const char*dirbuf, t_canvas*canvas) {
if(sys_isabsolutepath(dirbuf)) { // only include actual full paths
if (canvas) {
t_canvasenvironment *canvasenvironment = canvas_getenv(canvas);
canvasenvironment->ce_path = namelist_append(canvasenvironment->ce_path,
dirbuf, 0);
} else {
return libdir_add_to_globalpath(dirbuf);
}
return 1;
}
return 0;
}
static int libdir_loader_legacy(t_canvas *canvas, char *classname)
{
int fd = -1;
char fullclassname[FILENAME_MAX], dirbuf[FILENAME_MAX];
char *nameptr;
/* look for meta file (classname)/(classname)-meta.pd */
libdir_get_fullname(fullclassname, FILENAME_MAX, classname);
/* if this is being called from a canvas, then add the library path to the
* canvas-local path */
if(canvas)
/* setting the canvas to NULL causes it to ignore any canvas-local path */
fd = canvas_open(NULL, fullclassname, ".pd",
dirbuf, &nameptr, FILENAME_MAX, 0);
else
fd = open_via_path(".", fullclassname, ".pd",
dirbuf, &nameptr, FILENAME_MAX, 0);
if(fd < 0)
{
return (0);
}
sys_close(fd);
#if 0
if(!canvas) {
char helppathname[FILENAME_MAX];
strncpy(helppathname, sys_libdir->s_name, FILENAME_MAX-30);
helppathname[FILENAME_MAX-30] = 0;
strcat(helppathname, "/doc/5.reference/");
strcat(helppathname, classname);
sys_helppath = namelist_append(sys_helppath, helppathname, 0);
}
#endif
if(libdir_add_to_path(dirbuf, canvas))
logpost(NULL, 3, "libdir_loader: added '%s' to the %s objectclass path",
classname, canvas?"canvas-local":"global");
/* post("libdir_loader loaded fullclassname: '%s'\n", fullclassname); */
logpost(NULL, 14, "Loaded libdir '%s' from '%s'", classname, dirbuf);
return (1);
}
static int libdir_loader_pathwise(t_canvas *canvas, const char *classname, const char*path)
{
int fd = -1;
char fullclassname[FILENAME_MAX], dirbuf[FILENAME_MAX];
char *nameptr;
if(!path) {
/* we already tried all paths, so skip this */
return 0;
}
/* look for meta file (classname)/(classname)-meta.pd */
libdir_get_fullname(fullclassname, FILENAME_MAX, classname);
if ((fd = sys_trytoopenone(path, fullclassname, ".pd",
dirbuf, &nameptr, FILENAME_MAX, 0)) < 0) {
return 0;
}
sys_close(fd);
if(libdir_add_to_path(dirbuf, canvas))
logpost(NULL, 3, "libdir_loader: added '%s' to the %s objectclass path",
classname, canvas?"canvas-local":"global");
/* post("libdir_loader loaded fullclassname: '%s'\n", fullclassname); */
logpost(NULL, 14, "Loaded libdir '%s' from '%s'", classname, dirbuf);
return (1);
}
static t_class *libdir_class;
static void*libdir_new(void)
{
t_pd *x = pd_new(libdir_class);
return (x);
}
void libdir_setup(void)
{
int major, minor, bugfix;
sys_getversion(&major, &minor, &bugfix);
if (major>0 || minor >=47) {
sys_register_loader((void*)libdir_loader_pathwise);
} else {
sys_register_loader((void*)libdir_loader_legacy);
}
logpost(NULL, 3, "libdir loader %s",version);
logpost(NULL, 3, "\tcompiled on "__DATE__" at "__TIME__ " ");
logpost(NULL, 3, "\tcompiled against Pd version %d.%d.%d.%s",
PD_MAJOR_VERSION, PD_MINOR_VERSION, PD_BUGFIX_VERSION, PD_TEST_VERSION);
libdir_class = class_new(gensym("libdir"), libdir_new, 0, sizeof(t_object), CLASS_NOINLET, 0);
}
void setup(void)
{
libdir_setup();
}