1 /*
2 namedins.c:
3
4 Copyright (C) 2002, 2005, 2006 Istvan Varga
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include "csoundCore.h"
25 #include "namedins.h"
26 #include "csound_orc_semantics.h"
27 #include <ctype.h>
28
29 /* check if the string s is a valid instrument or opcode name */
30 /* return value is zero if the string is not a valid name */
31
check_instr_name(char * s)32 int check_instr_name(char *s)
33 {
34 char *c = s;
35
36 if (UNLIKELY(!*c)) return 0; /* empty */
37 if (UNLIKELY(!isalpha(*c) &&
38 *c != '_')) return 0; /* chk if 1st char is valid */
39 while (*++c)
40 if (UNLIKELY(!isalnum(*c) && *c != '_')) return 0;
41 return 1; /* no errors */
42 }
43
44
named_instr_find_in_engine(CSOUND * csound,char * s,ENGINE_STATE * engineState)45 int32 named_instr_find_in_engine(CSOUND *csound, char *s,
46 ENGINE_STATE *engineState) {
47
48 INSTRNAME *inm;
49 int ss = (*s=='-'?1:0);
50
51 if (!engineState->instrumentNames)
52 return 0L; /* no named instruments defined */
53 /* now find instrument */
54 inm = cs_hash_table_get(csound, engineState->instrumentNames, s+ss);
55
56 return (inm == NULL) ? 0L : (ss ? -inm->instno : inm->instno);
57
58 }
59 /* find the instrument number for the specified name */
60 /* return value is zero if none was found */
61
named_instr_find(CSOUND * csound,char * s)62 int32 named_instr_find(CSOUND *csound, char *s)
63 {
64 return named_instr_find_in_engine(csound, s, &csound->engineState);
65 }
66
67
68 /* convert opcode string argument to instrument number */
69 /* return value is -1 if the instrument cannot be found */
70 /* (in such cases, csoundInitError() is also called) */
strarg2insno(CSOUND * csound,void * p,int is_string)71 int32 strarg2insno(CSOUND *csound, void *p, int is_string)
72 {
73 int32 insno;
74
75 if (is_string) {
76 if (UNLIKELY((insno = named_instr_find(csound, (char*) p)) <= 0)) {
77 csound->Message(csound, Str("WARNING: instr %s not found\n"), (char*) p);
78 return NOT_AN_INSTRUMENT;
79 }
80 }
81 else { /* numbered instrument */
82 insno = (int32) *((MYFLT*) p);
83 if (UNLIKELY(insno < 1 || insno > csound->engineState.maxinsno ||
84 !csound->engineState.instrtxtp[insno])) {
85 csound->Warning(csound, Str("Cannot Find Instrument %d"), (int) insno);
86 return csound->engineState.maxinsno;
87 }
88 }
89 return insno;
90 }
91
92 /* same as strarg2insno, but runs at perf time, */
93 /* and does not support numbered instruments */
94 /* (used by opcodes like event or schedkwhen) */
strarg2insno_p(CSOUND * csound,char * s)95 int32 strarg2insno_p(CSOUND *csound, char *s)
96 {
97 int32 insno;
98
99 if (UNLIKELY(!(insno = named_instr_find(csound, s)))) {
100 csound->ErrorMsg(csound, Str("instr %s not found"), s);
101 return NOT_AN_INSTRUMENT;
102 }
103 return insno;
104 }
105
106 /* convert opcode string argument to instrument number */
107 /* (also allows user defined opcode names); if the integer */
108 /* argument is non-zero, only opcode names are searched */
109 /* return value is -1 if the instrument cannot be found */
110 /* (in such cases, csoundInitError() is also called) */
strarg2opcno(CSOUND * csound,void * p,int is_string,int force_opcode)111 int32 strarg2opcno(CSOUND *csound, void *p, int is_string, int force_opcode)
112 {
113 int32 insno = 0;
114
115 if (!force_opcode) { /* try instruments first, if enabled */
116 if (is_string) {
117 insno = named_instr_find(csound, (char*) p);
118 }
119 else { /* numbered instrument */
120 insno = (int32) *((MYFLT*) p);
121 if (UNLIKELY(insno < 1 || insno > csound->engineState.maxinsno ||
122 !csound->engineState.instrtxtp[insno])) {
123 csound->InitError(csound, Str("Cannot Find Instrument %d"), (int) insno);
124 return NOT_AN_INSTRUMENT;
125 }
126 }
127 }
128 if (!insno && is_string) { /* if no instrument was found, */
129 OPCODINFO *inm = csound->opcodeInfo; /* search for user opcode */
130 while (inm && sCmp(inm->name, (char*) p)) inm = inm->prv;
131 if (inm) insno = (int32) inm->instno;
132 }
133 if (UNLIKELY(insno < 1)) {
134 csound->InitError(csound,
135 Str("cannot find the specified instrument or opcode"));
136 insno = NOT_AN_INSTRUMENT;
137 }
138 return insno;
139 }
140
141 /* create file name from opcode argument (string or MYFLT) */
142 /* CSOUND *csound: */
143 /* pointer to Csound instance */
144 /* char *s: */
145 /* output buffer, should have enough space; if NULL, the */
146 /* required amount of memory is allocated and returned */
147 /* void *p: */
148 /* opcode argument, is interpreted as char* or MYFLT*, */
149 /* depending on the 'is_string' parameter */
150 /* const char *baseName: */
151 /* name prefix to be used if the 'p' argument is MYFLT, */
152 /* and it is neither SSTRCOD, nor a valid index to strset */
153 /* space. */
154 /* For example, if "soundin." is passed as baseName, file */
155 /* names in the format "soundin.%d" will be generated. */
156 /* baseName may be an empty string, but should not be NULL */
157 /* int is_string: */
158 /* if non-zero, 'p' is interpreted as a char* pointer and */
159 /* is used as the file name. Otherwise, it is expected to */
160 /* point to a MYFLT value, and the following are tried: */
161 /* 1. if the value is SSTRCOD, the string argument of */
162 /* the current score event is used (string p-field) */
163 /* 2. if the value, rounded to the nearest integer, is a */
164 /* valid index to strset space, the strset string is */
165 /* used */
166 /* 3. the file name is generated using baseName and the */
167 /* value rounded to the nearest integer, as described */
168 /* above */
169 /* return value: */
170 /* pointer to the output string; if 's' is not NULL, it is */
171 /* always the same as 's', otherwise it is allocated with */
172 /* csound->Malloc() and the caller is responsible for */
173 /* freeing the allocated memory with csound->Free() or */
174 /* csound->Free() */
175
strarg2name(CSOUND * csound,char * s,void * p,const char * baseName,int is_string)176 char *strarg2name(CSOUND *csound, char *s, void *p, const char *baseName,
177 int is_string)
178 {
179 if (is_string) {
180 /* opcode string argument */
181 if (s == NULL)
182 s = csound->Malloc(csound, strlen((char*) p) + 1);
183 strcpy(s, (char*) p);
184 }
185 else if (csound->ISSTRCOD(*((MYFLT*) p))) {
186 /* p-field string, unquote and copy */
187 char *s2 = get_arg_string(csound, *((MYFLT*)p));
188 int i = 0;
189 //printf("strarg2name: %g %s\n", *((MYFLT*)p), s2);
190 if (s == NULL)
191 s = csound->Malloc(csound, strlen(s2) + 1);
192 if (*s2 == '"')
193 s2++;
194 while (*s2 != '"' && *s2 != '\0')
195 s[i++] = *(s2++);
196 s[i] = '\0';
197 }
198 else {
199 int i = (int) ((double) *((MYFLT*) p)
200 + (*((MYFLT*) p) >= FL(0.0) ? 0.5 : -0.5));
201 if (i >= 0 && i <= (int) csound->strsmax &&
202 csound->strsets != NULL && csound->strsets[i] != NULL) {
203 if (s == NULL)
204 s = csound->Malloc(csound, strlen(csound->strsets[i]) + 1);
205 strcpy(s, csound->strsets[i]);
206 }
207 else {
208 int n;
209 if (s == NULL) {
210 /* allocate +20 characters, assuming sizeof(int) <= 8 */
211 s = csound->Malloc(csound, n = strlen(baseName) + 21);
212 snprintf(s, n, "%s%d", baseName, i);
213 }
214 else sprintf(s, "%s%d", baseName, i); /* dubious */
215 }
216 }
217 return s;
218 }
219
220 /* ----------------------------------------------------------------------- */
221 /* the following functions are for efficient management of the opcode list */
222
223
224
225
226
227 /* -------- IV - Jan 29 2005 -------- */
228
229
230 /**
231 * Allocate nbytes bytes of memory that can be accessed later by calling
232 * csoundQueryGlobalVariable() with the specified name; the space is
233 * cleared to zero.
234 * Returns CSOUND_SUCCESS on success, CSOUND_ERROR in case of invalid
235 * parameters (zero nbytes, invalid or already used name), or
236 * CSOUND_MEMORY if there is not enough memory.
237 */
csoundCreateGlobalVariable(CSOUND * csound,const char * name,size_t nbytes)238 PUBLIC int csoundCreateGlobalVariable(CSOUND *csound,
239 const char *name, size_t nbytes)
240 {
241 void* p;
242 /* create new empty database if it does not exist yet */
243 if (UNLIKELY(csound->namedGlobals == NULL)) {
244 csound->namedGlobals = cs_hash_table_create(csound);
245 if (UNLIKELY(csound->namedGlobals == NULL))
246 return CSOUND_MEMORY;
247 }
248 /* check for valid parameters */
249 if (UNLIKELY(name == NULL))
250 return CSOUND_ERROR;
251 if (UNLIKELY(name[0] == '\0'))
252 return CSOUND_ERROR;
253 if (UNLIKELY(nbytes < (size_t) 1 || nbytes >= (size_t) 0x7F000000L))
254 return CSOUND_ERROR;
255
256 if (cs_hash_table_get(csound, csound->namedGlobals, (char*)name) != NULL)
257 return CSOUND_ERROR;
258
259 p = csound->Calloc(csound, nbytes);
260 if (UNLIKELY(p == NULL))
261 return CSOUND_MEMORY;
262
263 cs_hash_table_put(csound, csound->namedGlobals, (char*)name, p);
264 return CSOUND_SUCCESS;
265 }
266
267 /**
268 * Get pointer to space allocated with the name "name".
269 * Returns NULL if the specified name is not defined.
270 */
csoundQueryGlobalVariable(CSOUND * csound,const char * name)271 PUBLIC void *csoundQueryGlobalVariable(CSOUND *csound, const char *name)
272 {
273 /* check if there is an actual database to search */
274 if (csound->namedGlobals == NULL) return NULL;
275
276 /* check for a valid name */
277 if (UNLIKELY(name == NULL)) return NULL;
278 if (UNLIKELY(name[0] == '\0')) return NULL;
279
280 return cs_hash_table_get(csound, csound->namedGlobals, (char*) name);
281 }
282
283 /**
284 * This function is the same as csoundQueryGlobalVariable(), except the
285 * variable is assumed to exist and no error checking is done.
286 * Faster, but may crash or return an invalid pointer if 'name' is
287 * not defined.
288 */
csoundQueryGlobalVariableNoCheck(CSOUND * csound,const char * name)289 PUBLIC void *csoundQueryGlobalVariableNoCheck(CSOUND *csound, const char *name)
290 {
291 return cs_hash_table_get(csound, csound->namedGlobals, (char*) name);
292 }
293
294 /**
295 * Free memory allocated for "name" and remove "name" from the database.
296 * Return value is CSOUND_SUCCESS on success, or CSOUND_ERROR if the name is
297 * not defined.
298 */
csoundDestroyGlobalVariable(CSOUND * csound,const char * name)299 PUBLIC int csoundDestroyGlobalVariable(CSOUND *csound, const char *name)
300 {
301 void *p = cs_hash_table_get(csound, csound->namedGlobals, (char*)name);
302 if (UNLIKELY(p == NULL))
303 return CSOUND_ERROR;
304
305 csound->Free(csound, p);
306 cs_hash_table_remove(csound, csound->namedGlobals, (char*) name);
307
308 return CSOUND_SUCCESS;
309 }
310
311 /**
312 * Free entire global variable database. This function is for internal use
313 * only (e.g. by RESET routines).
314 */
csoundDeleteAllGlobalVariables(CSOUND * csound)315 void csoundDeleteAllGlobalVariables(CSOUND *csound)
316 {
317 if (csound == NULL || csound->namedGlobals == NULL) return;
318
319 cs_hash_table_mfree_complete(csound, csound->namedGlobals);
320 csound->namedGlobals = NULL;
321 }
322