aboutsummaryrefslogtreecommitdiff
path: root/shared/unstable/fragile.c
blob: d91ea588c9a4f7bafc44eab520cc1178efb2e33a (plain)
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/* Copyright (c) 1997-2005 Miller Puckette, krzYszcz, and others.
 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
 * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* Put here bits and pieces likely to break with any new Pd version. */

#include <string.h>
#include "m_pd.h"
#include "common/loud.h"
#include "unstable/pd_imp.h"
#include "unstable/fragile.h"

int fragile_class_count(void)
{
    return (pd_objectmaker->c_nmethod);
}

void fragile_class_getnames(t_atom *av)
{
    int ac = pd_objectmaker->c_nmethod;
    t_methodentry *mp = pd_objectmaker->c_methods;
    while (ac--)
    {
	SETSYMBOL(av, mp->me_name);
	mp++; av++;
    }
}

/* Raising and voluntary mutation is a method of resolving name clashes.
   A raised class hides other equivocal candidates.  A simpler method,
   raising and lowering, works only in global scope, because, currently, Pd
   has only one visibility stack.  Until this is changed, abstraction scope
   will involve some kind of a hack for overriding global visibility stack. */

void fragile_class_raise(t_symbol *cname, t_newmethod thiscall)
{
    t_methodentry *mp = pd_objectmaker->c_methods, *topmp = 0;
    int count = pd_objectmaker->c_nmethod;
    while (count--)
    {
	if (mp->me_name == cname)
	{
	    if (mp->me_fun == (t_gotfn)thiscall)
	    {
		if (topmp)
		{
		    t_methodentry auxmp;
		    /* no linkage there, but anyway... */
		    loud_warning(0, 0, "%s is raising itself...",
				 cname->s_name);
		    memcpy(&auxmp, mp, sizeof(t_methodentry));
		    memcpy(mp, topmp, sizeof(t_methodentry));
		    memcpy(topmp, &auxmp, sizeof(t_methodentry));
		}
		return;
	    }
	    else if (!topmp)
		topmp = mp;
	}
	mp++;
    }
    loudbug_bug("fragile_class_raise");
}

t_pd *fragile_class_mutate(t_symbol *cname, t_newmethod thiscall,
			   int ac, t_atom *av)
{
    t_newmethod fn;
    t_atomtype *argtypes;
    if (fn = fragile_class_getalien(cname, thiscall, &argtypes))
    {
	t_pd *z;
	loud_warning(0, 0, "%s is mutating now...", cname->s_name);
	if (z = fragile_class_createobject(cname, fn, argtypes, ac, av))
	{
	    post("...succeeded");
	    return (z);
	}
	else post("...failed");
    }
    return (0);
}

t_newmethod fragile_class_getalien(t_symbol *cname, t_newmethod thiscall,
				   t_atomtype **argtypesp)
{
    t_methodentry *mp = pd_objectmaker->c_methods;
    int count = pd_objectmaker->c_nmethod;
    while (count--)
    {
	if (mp->me_name == cname && mp->me_fun != (t_gotfn)thiscall)
	{
	    *argtypesp = mp->me_arg;
	    return ((t_newmethod)mp->me_fun);
	}
	mp++;
    }
    return (0);
}

/* A specialized copy of pd_typedmess() from m_class.c,
   somewhat simplified for readability. */

typedef t_pd *(*t_newgimme)(t_symbol *s, int ac, t_atom *av);
typedef t_pd *(*t_new0)(
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
typedef t_pd *(*t_new1)(
    t_symbol*,
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
typedef t_pd *(*t_new2)(
    t_symbol*, t_symbol*,
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
typedef t_pd *(*t_new3)(
    t_symbol*, t_symbol*, t_symbol*,
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
typedef t_pd *(*t_new4)(
    t_symbol*, t_symbol*, t_symbol*, t_symbol*,
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
typedef t_pd *(*t_new5)(
    t_symbol*, t_symbol*, t_symbol*, t_symbol*, t_symbol*,
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
typedef t_pd *(*t_new6)(
    t_symbol*, t_symbol*, t_symbol*, t_symbol*, t_symbol*, t_symbol*,
    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);

t_pd *fragile_class_createobject(t_symbol *cname, t_newmethod callthis,
				 t_atomtype *argtypes, int ac, t_atom *av)
{
    t_floatarg ff[MAXPDARG+1], *fp = ff;
    t_symbol *ss[MAXPDARG+1], **sp = ss;
    int nsymbols = 0;
    t_atomtype wanttype;
    if (*argtypes == A_GIMME)
	return ((*((t_newgimme)(callthis)))(cname, ac, av));
    if (ac > MAXPDARG)
	ac = MAXPDARG;
    while (wanttype = *argtypes++)
    {
	switch (wanttype)
	{
	case A_POINTER:
	    goto badarg;
	case A_FLOAT:
	    if (!ac) goto badarg;
	case A_DEFFLOAT:
	    if (!ac) *fp = 0;
	    else
	    {
		if (av->a_type == A_FLOAT)
		    *fp = av->a_w.w_float;
		else goto badarg;
		ac--; av++;
	    }
	    fp++;
	    break;
	case A_SYMBOL:
	    if (!ac) goto badarg;
	case A_DEFSYM:
	    if (!ac) *sp = &s_;
	    else
	    {
		if (av->a_type == A_SYMBOL)
		    *sp = av->a_w.w_symbol;
		else if (av->a_type == A_FLOAT && av->a_w.w_float == 0)
		    *sp = &s_;
		else goto badarg;
		ac--; av++;
	    }
	    nsymbols++;
	    sp++;
	}
    }
    switch (nsymbols)
    {
    case 0: return ((*(t_new0)(callthis))
		    (ff[0], ff[1], ff[2], ff[3], ff[4]));
    case 1: return ((*(t_new1)(callthis))
		    (ss[0],
		     ff[0], ff[1], ff[2], ff[3], ff[4]));
    case 2: return ((*(t_new2)(callthis))
		    (ss[0], ss[1],
		     ff[0], ff[1], ff[2], ff[3], ff[4]));
    case 3: return ((*(t_new3)(callthis))
		    (ss[0], ss[1], ss[2],
		     ff[0], ff[1], ff[2], ff[3], ff[4]));
    case 4: return ((*(t_new4)(callthis))
		    (ss[0], ss[1], ss[2], ss[3],
		     ff[0], ff[1], ff[2], ff[3], ff[4]));
    case 5: return ((*(t_new5)(callthis))
		    (ss[0], ss[1], ss[2], ss[3], ss[4],
		     ff[0], ff[1], ff[2], ff[3], ff[4]));
    case 6: return ((*(t_new6)(callthis))
		    (ss[0], ss[1], ss[2], ss[3], ss[4], ss[5],
		     ff[0], ff[1], ff[2], ff[3], ff[4]));
    }
badarg:
    loud_error(0, "bad creation arguments for class '%s'", cname->s_name);
    return (0);
}

void fragile_class_printnames(char *msg, int firstndx, int lastndx)
{
    t_methodentry *mp = pd_objectmaker->c_methods;
    int ndx, len = strlen(msg);
    startpost(msg);
    for (ndx = firstndx, mp += ndx; ndx <= lastndx; ndx++, mp++)
    {
	t_symbol *s = mp->me_name;
	if (s && s->s_name[0] != '_')
	{
	    int l = 1 + strlen(s->s_name);
	    if ((len += l) > 66)
	    {
		endpost();
		startpost("   ");
		len = 3 + l;
	    }
	    poststring(s->s_name);
	}
    }
    endpost();
}

/* This structure is local to g_array.c.  We need it,
   because there is no other way to get into array's graph. */
struct _garray
{
    t_gobj x_gobj;
    t_glist *x_glist;
    /* ... */
};

t_glist *fragile_garray_glist(void *arr)
{
    return (((struct _garray *)arr)->x_glist);
}

/* This is local to m_obj.c.
   LATER export write access to o_connections field ('grab' class).
   LATER encapsulate 'traverseoutlet' routines (not in the stable API yet). */
struct _outlet
{
    t_object *o_owner;
    struct _outlet *o_next;
    t_outconnect *o_connections;
    t_symbol *o_sym;
};

/* obj_starttraverseoutlet() replacement */
t_outconnect *fragile_outlet_connections(t_outlet *o)
{
    return (o ? o->o_connections : 0);
}

t_outconnect *fragile_outlet_nextconnection(t_outconnect *last,
					    t_object **destp, int *innop)
{
    t_inlet *dummy;
    return (obj_nexttraverseoutlet(last, destp, &dummy, innop));
}

/* silent, if caller is empty */
t_object *fragile_outlet_destination(t_outlet *op,
				     int ntypes, t_symbol **types,
				     t_pd *caller, char *errand)
{
    t_object *booty = 0;
    t_symbol *badtype = 0;
    int count = 0;
    t_outconnect *tobooty = fragile_outlet_connections(op);
    while (tobooty)
    {
	t_object *ob;
	int inno;
	count++;
	tobooty = fragile_outlet_nextconnection(tobooty, &ob, &inno);
	if (ob && inno == 0)
	{
	    /* LATER ask for class_getname()'s symbol version */
	    t_symbol **tp, *dsttype = gensym(class_getname(*(t_pd *)ob));
	    int i;
	    for (i = 0, tp = types; i < ntypes; i++, tp++)
	    {
		if (*tp == dsttype)
		{
		    booty = ob;
		    break;
		}
		else badtype = dsttype;
	    }
	}
    }
    if (booty)
    {
	if (count > 1 && caller)
	    loud_warning(caller, 0, "multiple targets");
    }
    else if (caller)
    {
	if (badtype)
	    loud_error(caller, "bad target type '%s'", badtype->s_name);
	else
	    loud_error(caller, "no target");
	if (errand)
	    loud_errand(caller, errand);
    }
    return (booty);
}

/* These are local to m_obj.c. */
union inletunion
{
    t_symbol *iu_symto;
    t_gpointer *iu_pointerslot;
    t_float *iu_floatslot;
    t_symbol **iu_symslot;
    t_sample iu_floatsignalvalue;
};

struct _inlet
{
    t_pd i_pd;
    struct _inlet *i_next;
    t_object *i_owner;
    t_pd *i_dest;
    t_symbol *i_symfrom;
    union inletunion i_un;
};

/* simplified obj_findsignalscalar(), works for non-left inlets */
t_sample *fragile_inlet_signalscalar(t_inlet *i)
{
    return (&i->i_un.iu_floatsignalvalue);
}