1 /*
2 str_ops.c:
3
4 Copyright (C) 2005, 2006 Istvan Varga
5 (C) 2005 Matt J. Ingalls, John ffitch
6 (C) 2013 V Lazzarini (new string code)
7
8 This file is part of Csound.
9
10 The Csound Library is free software; you can redistribute it
11 and/or modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 Csound is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with Csound; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301 USA
24 */
25
26 #include "csoundCore.h"
27 #define CSOUND_STR_OPS_C 1
28 #include "str_ops.h"
29 #include <ctype.h>
30 #ifdef HAVE_CURL
31 #include <curl/curl.h>
32 #include "corfile.h"
33 #endif
34
35 #define STRSMAX 8
36
37 #ifndef HAVE_SNPRINTF
38 /* add any compiler/system that has snprintf() */
39 #if defined(HAVE_C99)
40 #define HAVE_SNPRINTF 1
41 #endif
42 #endif
43
s_opcode(CSOUND * csound,STRGET_OP * p)44 int32_t s_opcode(CSOUND *csound, STRGET_OP *p){
45 if (p->r->data == NULL){
46 p->r->data = (char *) csound->Malloc(csound, 15);
47 p->r->size = 15;
48 } else if (p->r->size < 15){
49 p->r->data = (char *) csound->ReAlloc(csound, p->r->data, 15);
50 p->r->size = 15;
51 }
52 snprintf(p->r->data, p->r->size, "%f", *p->indx);
53 return OK;
54 }
55
s_opcode_k(CSOUND * csound,STRGET_OP * p)56 int32_t s_opcode_k(CSOUND *csound, STRGET_OP *p){
57 IGN(csound);
58 snprintf(p->r->data, p->r->size, "%f", *p->indx);
59 return OK;
60 }
61
62 /* strset by John ffitch */
63
str_set(CSOUND * csound,int32_t ndx,const char * s)64 static void str_set(CSOUND *csound, int32_t ndx, const char *s)
65 {
66 if (UNLIKELY(csound->strsets == NULL)) {
67 csound->strsmax = STRSMAX;
68 csound->strsets = (char **) csound->Calloc(csound, (csound->strsmax + 1)
69 * sizeof(char*));
70 }
71 if (UNLIKELY(ndx > (int32_t) csound->strsmax)) {
72 int32_t i, newmax;
73 /* assumes power of two STRSMAX */
74 newmax = (ndx | (STRSMAX - 1)) + 1;
75 csound->strsets = (char**) csound->ReAlloc(csound, csound->strsets,
76 (newmax + 1) * sizeof(char*));
77 for (i = (csound->strsmax + 1); i <= newmax; i++)
78 csound->strsets[i] = NULL;
79 csound->strsmax = newmax;
80 }
81 if (UNLIKELY(ndx < 0)) { /* -ve index */
82 csound->InitError(csound, Str("illegal strset index"));
83 return;
84 }
85
86 if (csound->strsets[ndx] != NULL) {
87 if (strcmp(s, csound->strsets[ndx]) == 0)
88 return;
89 if (UNLIKELY(csound->oparms->msglevel & WARNMSG)) {
90 csound->Warning(csound, Str("strset index conflict at %d"), ndx);
91 csound->Warning(csound, Str("previous value: '%s', replaced with '%s'"),
92 csound->strsets[ndx], s);
93 }
94 csound->Free(csound, csound->strsets[ndx]);
95 }
96 csound->strsets[ndx] = (char*) csound->Malloc(csound, strlen(s) + 1);
97 strcpy(csound->strsets[ndx], s);
98 if ((csound->oparms->msglevel & 7) == 7)
99 csound->Message(csound, "Strsets[%d]: '%s'\n", ndx, s);
100 }
101
strset_init(CSOUND * csound,STRSET_OP * p)102 int32_t strset_init(CSOUND *csound, STRSET_OP *p)
103 {
104 str_set(csound, (int32_t) MYFLT2LRND(*p->indx), p->str->data);
105 return OK;
106 }
107
108 /* for argdecode.c */
109
strset_option(CSOUND * csound,char * s)110 void strset_option(CSOUND *csound, char *s)
111 {
112 int32_t indx = 0;
113
114 if (UNLIKELY(!isdigit(*s))) {
115 csound->Warning(csound, Str("--strset: invalid format"));
116 return;
117 }
118 do {
119 indx = (indx * 10) + (int32_t) (*s++ - '0');
120 } while (isdigit(*s));
121 if (UNLIKELY(*s++ != '=')){
122 csound->Warning(csound, Str("--strset: invalid format"));
123 return;
124 }
125 str_set(csound, indx, s);
126 }
127
strget_init(CSOUND * csound,STRGET_OP * p)128 int32_t strget_init(CSOUND *csound, STRGET_OP *p)
129 {
130 int32_t indx;
131 if (csound->ISSTRCOD(*(p->indx))) {
132 char *ss = csound->init_event->strarg;
133 if (ss == NULL)
134 return OK;
135 ss = get_arg_string(csound, *p->indx);
136 if (p->r->data == NULL) {
137 p->r->data = cs_strdup(csound, ss);
138 p->r->size = strlen(ss)+1;
139 }
140 else if ((int32_t) strlen(ss) >= p->r->size) {
141 csound->Free(csound, p->r->data);
142 p->r->data = cs_strdup(csound, ss);
143 p->r->size = strlen(ss) + 1;
144 }
145 else {
146 int32_t n = strlen(ss)+1;
147 p->r->size = n;
148 strNcpy(p->r->data, ss, n);
149 //p->r->data[p->r->size - 1] = '\0';
150 }
151 return OK;
152 }
153 indx = (int32_t)((double)*(p->indx) + (*(p->indx) >= FL(0.0) ? 0.5 : -0.5));
154 if (indx < 0 || indx > (int32_t) csound->strsmax ||
155 csound->strsets == NULL || csound->strsets[indx] == NULL)
156 return OK;
157 if (UNLIKELY((int32_t) strlen(csound->strsets[indx]) >= p->r->size)){
158 int32_t size = strlen(csound->strsets[indx]);
159 p->r->data = csound->ReAlloc(csound, p->r->data, size + 1);
160 p->r->size = size + 1;
161 }
162 strcpy((char*) p->r->data, csound->strsets[indx]);
163 return OK;
164 }
165
StrOp_ErrMsg(void * p,const char * msg)166 static CS_NOINLINE int32_t StrOp_ErrMsg(void *p, const char *msg)
167 {
168 CSOUND *csound = ((OPDS*) p)->insdshead->csound;
169 const char *opname = csound->GetOpcodeName(p);
170
171 if (UNLIKELY(csound->ids != NULL && csound->ids->insdshead == csound->curip))
172 return csound->InitError(csound, "%s: %s", opname, Str(msg));
173 else if (UNLIKELY(((OPDS*) p)->insdshead->pds != NULL))
174 return csound->PerfError(csound, (OPDS*)p,
175 "%s: %s", opname, Str(msg));
176 else
177 csound->Warning(csound, "%s: %s", opname, Str(msg));
178
179 return NOTOK;
180 }
181 /* strcpy */
strcpy_opcode_S(CSOUND * csound,STRCPY_OP * p)182 int32_t strcpy_opcode_S(CSOUND *csound, STRCPY_OP *p)
183 {
184 char *newVal = p->str->data;
185 if (p->r->data == NULL) {
186 p->r->data = cs_strdup(csound, newVal);
187 p->r->size = strlen(p->str->data) + 1;
188 //printf("NULL str:%p %p \n", p->r, p->r->data);
189 return OK;
190 }
191 if (p->r->data == p->str->data){
192 //printf("sameptr str:%p %p \n", p->r->data);
193 return OK;
194 }
195 if (UNLIKELY((int32_t) strlen(newVal) >= p->r->size)){
196 csound->Free(csound, p->r->data);
197 p->r->data = cs_strdup(csound, newVal);
198 p->r->size = strlen(newVal) + 1;
199 //printf("dup str:%p %p \n", p->r, p->r->data);
200 }
201 else {
202 strcpy((char*) p->r->data, newVal);
203 p->r->size = strlen(newVal) + 1;
204 //printf("str:%p %p \n", p->r, p->r->data);
205 }
206
207 return OK;
208 }
209
strassign_opcode_S(CSOUND * csound,STRCPY_OP * p)210 int32_t strassign_opcode_S(CSOUND *csound, STRCPY_OP *p)
211 {
212 IGN(csound);
213 p->r->data = p->str->data;
214 p->r->size = p->str->size;
215 return OK;
216 }
strassign_opcode_Sk(CSOUND * csound,STRCPY_OP * p)217 int32_t strassign_opcode_Sk(CSOUND *csound, STRCPY_OP *p)
218 {
219 IGN(csound);
220 if (strcmp(p->r->data, p->str->data)!=0){
221 p->r->data = p->str->data;
222 p->r->size = p->str->size;
223 }
224 //csound->Message(csound, p->r->data);
225 return OK;
226 }
227
str_changed(CSOUND * csound,STRCHGD * p)228 int32_t str_changed(CSOUND *csound, STRCHGD *p)
229 {
230 if (p->mem != NULL)
231 csound->Free(csound, p->mem);
232 p->mem = cs_strdup(csound, p->str->data);
233 *p->r = 0;
234 return OK;
235 }
236
str_changed_k(CSOUND * csound,STRCHGD * p)237 int32_t str_changed_k(CSOUND *csound, STRCHGD *p)
238 {
239 if (p->str->data && ( p->mem == NULL || strcmp(p->str->data, p->mem)!=0)) {
240 csound->Free(csound, p->mem);
241 p->mem = cs_strdup(csound, p->str->data);
242 *p->r = 1;
243 }
244 else *p->r = 0;
245 return OK;
246 }
247
248 extern char* get_strarg(CSOUND *csound, MYFLT p, char *strarg);
strcpy_opcode_p(CSOUND * csound,STRGET_OP * p)249 int32_t strcpy_opcode_p(CSOUND *csound, STRGET_OP *p)
250 {
251 if (csound->ISSTRCOD(*p->indx)) {
252 char *ss;
253 ss = get_arg_string(csound, *p->indx);
254 if (ss == NULL){
255 if (UNLIKELY(((OPDS*) p)->insdshead->pds != NULL))
256 return csoundPerfError(csound, (OPDS*)p,
257 Str("NULL string\n"));
258 else
259 return csoundInitError(csound, Str("NULL string\n"));
260 }
261 if (p->r->data == NULL) {
262 p->r->data = cs_strdup(csound, ss);
263 p->r->size = strlen(ss)+1;
264 }
265 else if ((int32_t) strlen(ss) >= p->r->size) {
266 csound->Free(csound, p->r->data);
267 p->r->data = cs_strdup(csound, ss);
268 p->r->size = strlen(ss) + 1;
269 }
270 else {
271 strcpy(p->r->data,ss);
272 p->r->size = strlen(ss) + 1;
273 }
274 }
275 else {
276 p->r->data = csound->strarg2name(csound, NULL, p->indx, "soundin.", 0);
277 p->r->size = strlen(p->r->data) + 1;
278 }
279
280 return OK;
281 }
282
283
284 /* strcat */
strcat_opcode(CSOUND * csound,STRCAT_OP * p)285 int32_t strcat_opcode(CSOUND *csound, STRCAT_OP *p)
286 {
287 int32_t size;
288 char *str1 = cs_strdup(csound, p->str1->data),
289 *str2 = cs_strdup(csound, p->str2->data);
290
291 if (str1 == NULL || str2 == NULL){
292 csound->Free(csound,str1);
293 csound->Free(csound,str2);
294 if (UNLIKELY(((OPDS*) p)->insdshead->pds != NULL))
295 return csoundPerfError(csound, (OPDS*)p, Str("NULL string\n"));
296 else return csoundInitError(csound, Str("NULL string\n"));
297 }
298
299 size = strlen(str1) + strlen(str2);
300
301 if (p->r->data == NULL) {
302 p->r->data = csound->Calloc(csound, size+1);
303 p->r->size = size+1;
304 }
305 else if (UNLIKELY((int32_t) size >= p->r->size)) {
306 char *nstr = csound->ReAlloc(csound, p->r->data, size + 1);
307 if (p->r->data == p->str1->data){
308 p->str1->data = nstr;
309 p->str1->size = size + 1;
310 }
311 if (p->r->data == p->str2->data){
312 p->str2->data = nstr;
313 p->str2->size = size + 1;
314 }
315 p->r->data = nstr;
316 p->r->size = size + 1;
317 }
318
319 strNcpy((char*) p->r->data, str1, p->r->size-1);
320 strcat((char*) p->r->data, str2);
321
322 csound->Free(csound, str2); /* not needed anymore */
323 csound->Free(csound, str1);
324 return OK;
325 }
326
327 /* strcmp */
328
strcmp_opcode(CSOUND * csound,STRCMP_OP * p)329 int32_t strcmp_opcode(CSOUND *csound, STRCMP_OP *p)
330 {
331 int32_t i;
332 if (p->str1->data == NULL || p->str2->data == NULL){
333 if (UNLIKELY(((OPDS*) p)->insdshead->pds != NULL))
334 return csoundPerfError(csound, (OPDS*)p, Str("NULL string\n"));
335 else return csoundInitError(csound, Str("NULL string\n"));
336 }
337
338 *(p->r) = FL(0.0);
339 if (p->str1 == p->str2)
340 return OK;
341 i = strcmp((char*) p->str1->data, (char*) p->str2->data);
342 if (i < 0)
343 *(p->r) = FL(-1.0);
344 else if (i > 0)
345 *(p->r) = FL(1.0);
346
347 return OK;
348 }
349
350 /* perform a sprintf-style format -- based on code by Matt J. Ingalls */
351
352 static CS_NOINLINE int32_t
sprintf_opcode_(CSOUND * csound,void * p,STRINGDAT * str,const char * fmt,MYFLT ** kvals,int32_t numVals,int32_t strCode)353 sprintf_opcode_(CSOUND *csound,
354 void *p, /* opcode data structure pointer */
355 STRINGDAT *str, /* pointer to space for output string */
356 const char *fmt, /* format string */
357 MYFLT **kvals, /* array of argument pointers */
358 int32_t numVals, /* number of arguments */
359 int32_t strCode) /* bit mask for string arguments */
360 {
361 int32_t len = 0;
362 char *strseg, *outstring = str->data;
363 MYFLT *parm = NULL;
364 int32_t i = 0, j = 0, n;
365 const char *segwaiting = NULL;
366 int32_t maxChars, siz = strlen(fmt) + numVals*7 + 1;
367
368 for (i = 0; i < numVals; i++) {
369 if (UNLIKELY(IS_ASIG_ARG(kvals[i]))) {
370 return StrOp_ErrMsg(p, Str("a-rate argument not allowed"));
371 }
372 }
373
374 if (UNLIKELY((int32_t) ((OPDS*) p)->optext->t.inArgCount > 31)){
375 StrOp_ErrMsg(p, Str("too many arguments"));
376 return NOTOK;
377 }
378 if (numVals==0) {
379 strcpy(str->data, fmt);
380 return OK;
381 }
382
383 strseg = csound->Malloc(csound, siz);
384 i = 0;
385
386 while (1) {
387 if (UNLIKELY(i >= siz)) {
388 // return StrOp_ErrMsg(p, "format string too long");
389 siz *= 2;
390 strseg = csound->ReAlloc(csound, strseg, siz);
391 }
392 if (*fmt != '%' && *fmt != '\0') {
393 strseg[i++] = *fmt++;
394 continue;
395 }
396 if (fmt[0] == '%' && fmt[1] == '%') {
397 strseg[i++] = *fmt++; /* Odd code: %% is usually % and as we
398 know the value of *fmt the loads are
399 unnecessary */
400 strseg[i++] = *fmt++;
401
402 continue;
403 }
404
405 /* if already a segment waiting, then lets print it */
406 if (segwaiting != NULL) {
407
408 maxChars = str->size - len;
409 strseg[i] = '\0';
410 if (UNLIKELY(numVals <= 0)) {
411 csound->Free(csound, strseg);
412 return StrOp_ErrMsg(p, Str("insufficient arguments for format"));
413 }
414 numVals--;
415 /* if (UNLIKELY((*segwaiting == 's' && !(strCode & 1)) || */
416 /* (*segwaiting != 's' && (strCode & 1)))) { */
417 /* return StrOp_ErrMsg(p, "argument type inconsistent with format"); */
418 /* } */
419 strCode >>= 1;
420 parm = kvals[j++];
421
422 switch (*segwaiting) {
423 case 'd':
424 case 'i':
425 case 'o':
426 case 'x':
427 case 'X':
428 case 'u':
429 case 'c':
430 #ifdef HAVE_SNPRINTF
431 if ((int32_t)strlen(strseg) + 24 > (int32_t)maxChars) {
432 int32_t offs = outstring - str->data;
433 str->data = csound->ReAlloc(csound, str->data,
434 str->size + 24);
435 if(str->data == NULL) {
436 return StrOp_ErrMsg(p, Str("memory allocation failure"));
437 }
438 str->size += 24;
439 maxChars += 24;
440 outstring = str->data + offs;
441 //printf("maxchars = %d %s\n", maxChars, strseg);
442 //printf("size: %d \n",str->size);
443
444 }
445 n = snprintf(outstring, maxChars, strseg, (int32_t) MYFLT2LRND(*parm));
446 #else
447 n = sprintf(outstring, strseg, (int32_t) MYFLT2LRND(*parm));
448 #endif
449 break;
450 case 'e':
451 case 'E':
452 case 'f':
453 case 'F':
454 case 'g':
455 case 'G':
456 #ifdef HAVE_SNPRINTF
457 //printf("%d %d \n", str->size, strlen(str->data));
458 if (strlen(strseg) + 24 > (uint32_t)maxChars) {
459 int32_t offs = outstring - str->data;
460 str->data = csound->ReAlloc(csound, str->data, str->size + 13);
461 if(str->data == NULL) {
462 return StrOp_ErrMsg(p, Str("memory allocation failure"));
463 }
464 str->size += 24;
465 maxChars += 24;
466 outstring = str->data + offs;
467 //printf("maxchars = %d %s\n", maxChars, strseg);
468 }
469 //printf("%d %d \n", str->size, strlen(str->data));
470 n = snprintf(outstring, maxChars, strseg, (double)*parm);
471 #else
472 n = sprintf(outstring, strseg, (double)*parm);
473 #endif
474 break;
475 case 's':
476 if (((STRINGDAT*)parm)->data == str->data) {
477 csound->Free(csound, strseg);
478 return StrOp_ErrMsg(p, Str("output argument may not be "
479 "the same as any of the input args"));
480 }
481 if ((((STRINGDAT*)parm)->size+strlen(strseg)) >= (uint32_t)maxChars) {
482 int32_t offs = outstring - str->data;
483 str->data = csound->ReAlloc(csound, str->data,
484 str->size + ((STRINGDAT*)parm)->size +
485 strlen(strseg));
486 if(str->data == NULL){
487 return StrOp_ErrMsg(p, Str("memory allocation failure"));
488 }
489 str->size += ((STRINGDAT*)parm)->size + strlen(strseg);
490 maxChars += ((STRINGDAT*)parm)->size + strlen(strseg);
491 outstring = str->data + offs;
492 }
493 n = snprintf(outstring, maxChars, strseg, ((STRINGDAT*)parm)->data);
494 break;
495 default:
496 csound->Free(csound, strseg);
497 return StrOp_ErrMsg(p, Str("invalid format string"));
498 }
499 if (n < 0 || n >= maxChars) {
500 /* safely detected excess string length */
501 int32_t offs = outstring - str->data;
502 str->data = csound->ReAlloc(csound, str->data, maxChars*2);
503 if (str->data == NULL) {
504 return StrOp_ErrMsg(p, Str("memory allocation failure"));
505 }
506 outstring = str->data + offs;
507 str->size = maxChars*2;
508 // VL: Coverity says this is unused. (which is true)
509 // maxChars += str->size;
510
511 }
512 outstring += n;
513 len += n;
514 i = 0;
515 }
516
517 if (*fmt == '\0')
518 break;
519 /* copy the '%' */
520 strseg[i++] = *fmt++;
521 /* find the format code */
522 segwaiting = fmt;
523
524 while (!isalpha(*segwaiting) && *segwaiting != '\0')
525 segwaiting++;
526 }
527 if (UNLIKELY(numVals > 0)) {
528 csound->Free(csound, strseg);
529 return StrOp_ErrMsg(p, Str("too many arguments for format"));
530 }
531 csound->Free(csound, strseg);
532 return OK;
533 }
534
sprintf_opcode(CSOUND * csound,SPRINTF_OP * p)535 int32_t sprintf_opcode(CSOUND *csound, SPRINTF_OP *p)
536 {
537 int32_t size = p->sfmt->size+ 18*((int32_t) p->INOCOUNT);
538 //printf("%d %d \n", p->r->size, strlen(p->r->data));
539 if (p->r->data == NULL || p->r->size < size) {
540 /* this 10 is 1n incorrect guess which is OK with numbers*/
541 p->r->data = csound->Calloc(csound, size);
542 p->r->size = size;
543 }
544 if (UNLIKELY(sprintf_opcode_(csound, p, p->r,
545 (char*) p->sfmt->data, &(p->args[0]),
546 (int32_t) p->INOCOUNT - 1,0) == NOTOK)) {
547 ((char*) p->r->data)[0] = '\0';
548 return NOTOK;
549 }
550 return OK;
551 }
552
printf_opcode_(CSOUND * csound,PRINTF_OP * p)553 static CS_NOINLINE int32_t printf_opcode_(CSOUND *csound, PRINTF_OP *p)
554 {
555 STRINGDAT buf;
556 int32_t err;
557 buf.size = /*strlen(p->sfmt->data) +*/ 3072;
558 buf.data = csound->Calloc(csound, buf.size);
559
560 err = sprintf_opcode_(csound, p, &buf, (char*) p->sfmt->data, &(p->args[0]),
561 (int32_t) p->INOCOUNT - 2,0);
562 if (LIKELY(err == OK))
563 csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", buf.data);
564 csound->Free(csound, buf.data);
565
566 return err;
567 }
568
printf_opcode_init(CSOUND * csound,PRINTF_OP * p)569 int32_t printf_opcode_init(CSOUND *csound, PRINTF_OP *p)
570 {
571 if (*p->ktrig > FL(0.0))
572 return (printf_opcode_(csound, p));
573 return OK;
574 }
575
printf_opcode_set(CSOUND * csound,PRINTF_OP * p)576 int32_t printf_opcode_set(CSOUND *csound, PRINTF_OP *p)
577 {
578 (void) csound;
579 p->prv_ktrig = FL(0.0);
580 return OK;
581 }
582
printf_opcode_perf(CSOUND * csound,PRINTF_OP * p)583 int32_t printf_opcode_perf(CSOUND *csound, PRINTF_OP *p)
584 {
585 MYFLT ktrig = *p->ktrig;
586 if (ktrig == p->prv_ktrig)
587 return OK;
588 p->prv_ktrig = ktrig;
589 if (ktrig > FL(0.0))
590 return (printf_opcode_(csound, p));
591 return OK;
592 }
593
puts_opcode_init(CSOUND * csound,PUTS_OP * p)594 int32_t puts_opcode_init(CSOUND *csound, PUTS_OP *p)
595 {
596 p->noNewLine = (*p->no_newline == FL(0.0) ? 0 : 1);
597 if (*p->ktrig > FL(0.0)) {
598 if (!p->noNewLine)
599 csound->MessageS(csound, CSOUNDMSG_ORCH, "%s\n", (char*) p->str->data);
600 else
601 csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", (char*) p->str->data);
602 }
603 p->prv_ktrig = *p->ktrig;
604
605 return OK;
606 }
607
puts_opcode_perf(CSOUND * csound,PUTS_OP * p)608 int32_t puts_opcode_perf(CSOUND *csound, PUTS_OP *p)
609 {
610 if (*p->ktrig != p->prv_ktrig && *p->ktrig > FL(0.0)) {
611 p->prv_ktrig = *p->ktrig;
612 if (!p->noNewLine)
613 csound->MessageS(csound, CSOUNDMSG_ORCH, "%s\n", (char*) p->str->data);
614 else
615 csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", (char*) p->str->data);
616 }
617
618 return OK;
619 }
620
strtod_opcode_p(CSOUND * csound,STRTOD_OP * p)621 int32_t strtod_opcode_p(CSOUND *csound, STRTOD_OP *p)
622 {
623 char *s = NULL, *tmp;
624 double x;
625
626 if (csound->ISSTRCOD(*p->str))
627 s = get_arg_string(csound, *p->str);
628 else {
629 int32_t ndx = (int32_t) MYFLT2LRND(*p->str);
630 if (ndx >= 0 && ndx <= (int32_t) csound->strsmax && csound->strsets != NULL)
631 s = csound->strsets[ndx];
632 }
633 if (UNLIKELY(s == NULL))
634 return StrOp_ErrMsg(p, Str("empty string"));
635 while (isblank(*s)) s++;
636 if (UNLIKELY(*s == '\0'))
637 return StrOp_ErrMsg(p, Str("empty string"));
638 x = cs_strtod(s, &tmp);
639 if (UNLIKELY(*tmp != '\0'))
640 return StrOp_ErrMsg(p, Str("invalid format"));
641 *p->indx = (MYFLT) x;
642
643 return OK;
644 }
645
strtod_opcode_S(CSOUND * csound,STRSET_OP * p)646 int32_t strtod_opcode_S(CSOUND *csound, STRSET_OP *p)
647 {
648 IGN(csound);
649 char *s = NULL, *tmp;
650 double x;
651 s = (char*) p->str->data;
652 while (isblank(*s)) s++;
653 if (UNLIKELY(*s == '\0'))
654 return StrOp_ErrMsg(p, Str("empty string"));
655 x = cs_strtod(s, &tmp);
656 if (UNLIKELY(*tmp != '\0'))
657 return StrOp_ErrMsg(p, Str("invalid format"));
658 *p->indx = (MYFLT) x;
659
660 return OK;
661 }
662
strtol_opcode_S(CSOUND * csound,STRSET_OP * p)663 int32_t strtol_opcode_S(CSOUND *csound, STRSET_OP *p)
664 {
665 IGN(csound);
666 char *s = NULL;
667 int32_t sgn = 0, radix = 10;
668 int32_t x = 0;
669
670 s = (char*) p->str->data;
671 while (isblank(*s)) s++;
672 if (UNLIKELY(*s == '\0'))
673 return StrOp_ErrMsg(p, Str("empty string"));
674 if (*s == '+') s++;
675 else if (*s == '-') sgn++, s++;
676 if (*s == '0') {
677 if (s[1] == 'x' || s[1] == 'X')
678 radix = 16, s += 2;
679 else if (s[1] != '\0')
680 radix = 8, s++;
681 else {
682 *p->indx = FL(0.0);
683 return OK;
684 }
685 }
686 if (UNLIKELY(*s == '\0'))
687 return StrOp_ErrMsg(p, Str("invalid format"));
688 switch (radix) {
689 case 8:
690 while (*s >= '0' && *s <= '7') x = (x * 8L) + (int32_t) (*s++ - '0');
691 break;
692 case 10:
693 while (isdigit(*s)) x = (x * 10L) + (int32_t) (*s++ - '0');
694 break;
695 default:
696 while (1) {
697 if (isdigit(*s))
698 x = (x * 16L) + (int32_t) (*s++ - '0');
699 else if (*s >= 'A' && *s <= 'F')
700 x = (x * 16L) + (int32_t) (*s++ - 'A') + 10L;
701 else if (*s >= 'a' && *s <= 'f')
702 x = (x * 16L) + (int32_t) (*s++ - 'a') + 10L;
703 else
704 break;
705 }
706 }
707 if (UNLIKELY(*s != '\0'))
708 return StrOp_ErrMsg(p, Str("invalid format"));
709 if (sgn) x = -x;
710 *p->indx = (MYFLT) x;
711
712 return OK;
713 }
714
715
strtol_opcode_p(CSOUND * csound,STRTOD_OP * p)716 int32_t strtol_opcode_p(CSOUND *csound, STRTOD_OP *p)
717 {
718 char *s = NULL;
719 int32_t sgn = 0, radix = 10;
720 int32_t x = 0L;
721
722 if (csound->ISSTRCOD(*p->str))
723 s = get_arg_string(csound, *p->str);
724 else {
725 int32_t ndx = (int32_t) MYFLT2LRND(*p->str);
726 if (ndx >= 0 && ndx <= (int32_t) csound->strsmax && csound->strsets != NULL)
727 s = csound->strsets[ndx];
728 }
729 if (UNLIKELY(s == NULL))
730 return StrOp_ErrMsg(p, Str("empty string"));
731
732 while (isblank(*s)) s++;
733 if (UNLIKELY(*s == '\0'))
734 return StrOp_ErrMsg(p, Str("empty string"));
735 if (*s == '+') s++;
736 else if (*s == '-') sgn++, s++;
737 if (*s == '0') {
738 if (s[1] == 'x' || s[1] == 'X')
739 radix = 16, s += 2;
740 else if (s[1] != '\0')
741 radix = 8, s++;
742 else {
743 *p->indx = FL(0.0);
744 return OK;
745 }
746 }
747 if (UNLIKELY(*s == '\0'))
748 return StrOp_ErrMsg(p, Str("invalid format"));
749 switch (radix) {
750 case 8:
751 while (*s >= '0' && *s <= '7') x = (x * 8L) + (int32_t) (*s++ - '0');
752 break;
753 case 10:
754 while (isdigit(*s)) x = (x * 10L) + (int32_t) (*s++ - '0');
755 break;
756 default:
757 while (1) {
758 if (isdigit(*s))
759 x = (x * 16L) + (int32_t) (*s++ - '0');
760 else if (*s >= 'A' && *s <= 'F')
761 x = (x * 16L) + (int32_t) (*s++ - 'A') + 10L;
762 else if (*s >= 'a' && *s <= 'f')
763 x = (x * 16L) + (int32_t) (*s++ - 'a') + 10L;
764 else
765 break;
766 }
767 }
768 if (UNLIKELY(*s != '\0'))
769 return StrOp_ErrMsg(p, Str("invalid format"));
770 if (sgn) x = -x;
771 *p->indx = (MYFLT) x;
772
773 return OK;
774 }
775
776 /**
777 * Sdst strsub Ssrc[, istart[, iend]]
778 * Sdst strsubk Ssrc, kstart, kend
779 *
780 * Extract a part of Ssrc, from istart to iend; if istart or iend is
781 * less than 0, or greater than the length of the source string, it is
782 * interpreted as the end of the source string. istart > iend will
783 * reverse the string. The default parameters are istart = 0, iend = -1.
784 */
785
strsub_opcode(CSOUND * csound,STRSUB_OP * p)786 int32_t strsub_opcode(CSOUND *csound, STRSUB_OP *p)
787 {
788 const char *src;
789 char *dst;
790 int32_t i, len, strt, end, rev = 0;
791
792 if (p->Ssrc->data == NULL) return NOTOK;
793 if (p->Sdst->data == NULL || p->Sdst->size < p->Ssrc->size) {
794 int32_t size = p->Ssrc->size;
795 if (p->Sdst->data != NULL) csound->Free(csound, p->Sdst->data);
796 p->Sdst->data = csound->Calloc(csound, size);
797 p->Sdst->size = size;
798 }
799
800 src = (char*) p->Ssrc->data;
801 dst = (char*) p->Sdst->data;
802 len = (int32_t) strlen(src);
803 #if defined(MSVC) || (defined(__GNUC__) && defined(__i386__))
804 strt = (int32_t) MYFLT2LRND(*(p->istart));
805 end = (int32_t) MYFLT2LRND(*(p->iend));
806 #else
807 strt = (int32_t) (*(p->istart) + FL(1.5)) - 1;
808 end = (int32_t) (*(p->iend) + FL(1.5)) - 1;
809 #endif
810 if (strt < 0 || strt > len)
811 strt = len;
812 if (end < 0 || end > len)
813 end = len;
814 if (strt == end) {
815 /* trivial case: empty output */
816 dst[0] = '\0';
817 return OK;
818 }
819 if (strt > end) {
820 int32_t tmp = strt;
821 /* reverse output */
822 strt = end;
823 end = tmp;
824 rev = 1;
825 }
826
827 src += strt;
828 len = end - strt;
829 if (UNLIKELY(len >= p->Sdst->size)) {
830 p->Sdst->data = csound->ReAlloc(csound, p->Sdst->data, len+1);
831 p->Sdst->size = len+1;
832 dst = (char*) p->Sdst->data;
833 }
834 i = 0;
835 if (!rev || p->Sdst->data == p->Ssrc->data) {
836 /* copying in forward direction is safe */
837 /* even if Ssrc and Sdst are the same */
838 do {
839 dst[i] = src[i];
840 } while (++i < len);
841 dst[i] = '\0';
842 if (rev) {
843 int32_t j;
844 /* if the destination string variable is the same as the source, */
845 /* reversing needs to be handled in a special way */
846 i = 0;
847 j = len - 1;
848 while (i < j) {
849 char tmp = dst[i];
850 dst[i++] = dst[j];
851 dst[j--] = tmp;
852 }
853 }
854 }
855 else {
856 /* reverse string out of place (Ssrc and Sdst are not the same) */
857 int32_t j = len;
858 do {
859 dst[i] = src[--j];
860 } while (++i < len);
861 dst[i] = '\0';
862 }
863 return OK;
864 }
865
866 /**
867 * ichr strchar Sstr[, ipos]
868 * kchr strchark Sstr[, kpos]
869 *
870 * Return the ASCII code of the character in Sstr at ipos (defaults to 0).
871 * If ipos is out of range, 0 is returned.
872 */
873
strchar_opcode(CSOUND * csound,STRCHAR_OP * p)874 int32_t strchar_opcode(CSOUND *csound, STRCHAR_OP *p)
875 {
876 int32_t len = (int32_t) strlen((char*) p->Ssrc->data);
877 #if defined(MSVC) || (defined(__GNUC__) && defined(__i386__))
878 int32_t pos = (int32_t) MYFLT2LRND(*(p->ipos));
879 #else
880 int32_t pos = (int32_t) (*(p->ipos) + FL(1.5)) - 1;
881 #endif
882
883 (void) csound;
884 if (pos < 0 || pos >= len)
885 *(p->ichr) = FL(0.0);
886 else
887 *(p->ichr) = (MYFLT) ((int32_t)((unsigned char)((char*) p->Ssrc->data)[pos]));
888
889 return OK;
890 }
891
892 /**
893 * ilen strlen Sstr
894 * klen strlenk Sstr
895 *
896 * Return the length of a string.
897 */
898
strlen_opcode(CSOUND * csound,STRLEN_OP * p)899 int32_t strlen_opcode(CSOUND *csound, STRLEN_OP *p)
900 {
901 (void) csound;
902 if (p->Ssrc->size)
903 *(p->ilen) = (MYFLT) strlen(p->Ssrc->data);
904 else *(p->ilen) = FL(0.0);
905 return OK;
906 }
907
908 /**
909 * Sdst strupper Ssrc
910 * Sdst strupperk Ssrc
911 * Sdst strlower Ssrc
912 * Sdst strlowerk Ssrc
913 *
914 * Convert a string to upper or lower case.
915 */
916
strupper_opcode(CSOUND * csound,STRUPPER_OP * p)917 int32_t strupper_opcode(CSOUND *csound, STRUPPER_OP *p)
918 {
919 const char *src;
920 char *dst;
921 int32_t i;
922 if (p->Ssrc->data == NULL) return NOTOK;
923 if (p->Sdst->data == NULL || p->Sdst->size < p->Ssrc->size) {
924 int32_t size = p->Ssrc->size;
925 if (p->Sdst->data != NULL) csound->Free(csound, p->Sdst->data);
926 p->Sdst->data = csound->Calloc(csound, size);
927 p->Sdst->size = size;
928 }
929
930 (void) csound;
931 src = (char*) p->Ssrc->data;
932 dst = (char*) p->Sdst->data;
933 for (i = 0; src[i] != '\0'; i++) {
934 unsigned char tmp;
935 tmp = (unsigned char) src[i];
936 dst[i] = (char) (islower(tmp) ? (unsigned char) toupper(tmp) : tmp);
937 }
938
939 return OK;
940 }
941
strlower_opcode(CSOUND * csound,STRUPPER_OP * p)942 int32_t strlower_opcode(CSOUND *csound, STRUPPER_OP *p)
943 {
944 const char *src;
945 char *dst;
946 int32_t i;
947 if (p->Ssrc->data == NULL) return NOTOK;
948 if (p->Sdst->data == NULL || p->Sdst->size < p->Ssrc->size) {
949 int32_t size = p->Ssrc->size;
950 if (p->Sdst->data != NULL) csound->Free(csound,p->Sdst->data);
951 p->Sdst->data = csound->Calloc(csound, size);
952 p->Sdst->size = size;
953 }
954
955 (void) csound;
956 src = (char*) p->Ssrc->data;
957 dst = (char*) p->Sdst->data;
958 for (i = 0; src[i] != '\0'; i++) {
959 unsigned char tmp;
960 tmp = (unsigned char) src[i];
961 dst[i] = (char) (isupper(tmp) ? (unsigned char) tolower(tmp) : tmp);
962 }
963
964 return OK;
965 }
966
967 /**
968 * Sval getcfg iopt
969 *
970 * Returns the value of a global setting (e.g. input file name) as a
971 * string.
972 */
973
getcfg_opcode(CSOUND * csound,GETCFG_OP * p)974 int32_t getcfg_opcode(CSOUND *csound, GETCFG_OP *p)
975 {
976 const char *s;
977 #if defined(MSVC) || (defined(__GNUC__) && defined(__i386__))
978 int32_t opt = (int32_t) MYFLT2LRND(*(p->iopt));
979 #else
980 int32_t opt = (int32_t) (*(p->iopt) + FL(0.5));
981 #endif
982 char buf[32];
983
984 if (p->Sdst->size < 32){
985 csound->Free(csound, p->Sdst->data);
986 p->Sdst->data = csound->Calloc(csound,32);
987 p->Sdst->size = 32;
988 }
989 //((char*) p->Sdst->data)[0] = '\0';
990 buf[0] = '\0';
991 s = &(buf[0]);
992 switch (opt) {
993 case 1: /* maximum length of variable */
994 snprintf(&(buf[0]), 32, "%d", (int32_t) p->Sdst->size - 1);
995 break;
996 case 2: /* input sound file name */
997 s = (csound->oparms->sfread && !csound->initonly ?
998 csound->oparms->infilename : (char*) NULL);
999 break;
1000 case 3: /* output sound file name */
1001 s = (csound->oparms->sfwrite && !csound->initonly ?
1002 csound->oparms->outfilename : (char*) NULL);
1003 break;
1004 case 4: /* is real-time audio being used ? (0: no, 1: yes) */
1005 buf[0] = '0';
1006 buf[1] = '\0';
1007 if ((csound->oparms->sfread && !csound->initonly &&
1008 check_rtaudio_name(csound->oparms->infilename, NULL, 0) >= 0) ||
1009 (csound->oparms->sfwrite && !csound->initonly &&
1010 check_rtaudio_name(csound->oparms->outfilename, NULL, 1) >= 0))
1011 buf[0] = '1';
1012 break;
1013 case 5: /* is beat mode being used ? (0: no, 1: yes) */
1014 buf[0] = (csound->oparms->Beatmode ? '1' : '0');
1015 buf[1] = '\0';
1016 break;
1017 case 6: /* host OS name */
1018 #ifdef LINUX
1019 s = "Linux";
1020 #elif defined(WIN32)
1021 s = "Win32";
1022 #elif defined(MACOSX)
1023 s = "MacOSX";
1024 #else
1025 s = "unknown";
1026 #endif
1027 break;
1028 case 7: /* is the channel I/O callback set ? (0: no, 1: yes) */
1029 buf[0] = 0;
1030 buf[1] = '\0';
1031 break;
1032 default:
1033 return csound->InitError(csound, Str("invalid option code: %g"),
1034 *(p->iopt));
1035 }
1036 if (s != NULL) {
1037
1038 if (p->Sdst->data == NULL) {
1039 int32_t size = strlen(s) + 1;
1040 p->Sdst->data = csound->Calloc(csound, size);
1041 p->Sdst->size = size;
1042 }
1043 else if (UNLIKELY((int32_t) strlen(s) >= p->Sdst->size)) {
1044 p->Sdst->data = csound->ReAlloc(csound, p->Sdst->data, strlen(s) + 1);
1045 p->Sdst->size = strlen(s) + 1;
1046 }
1047 strcpy((char*) p->Sdst->data, s);
1048 }
1049 return OK;
1050 }
1051
1052 /**
1053 * ipos strindex Sstr1, Sstr2
1054 * kpos strindexk Sstr1, Sstr2
1055 *
1056 * Return the position of the first occurence of Sstr2 in Sstr1,
1057 * or -1 if not found. If Sstr2 is empty, 0 is returned.
1058 */
1059
strindex_opcode(CSOUND * csound,STRINDEX_OP * p)1060 int32_t strindex_opcode(CSOUND *csound, STRINDEX_OP *p)
1061 {
1062 const char *s1 = (char*) p->Ssrc1->data;
1063 const char *s2 = (char*) p->Ssrc2->data;
1064 int32_t i, j;
1065
1066 (void) csound;
1067 /* search substring from left to right, */
1068 /* and return position of first match */
1069 i = j = 0;
1070 while (s2[j] != '\0') {
1071 if (s1[i] == '\0') {
1072 *(p->ipos) = -FL(1.0);
1073 return OK;
1074 }
1075 j = (s1[i] != s2[j] ? 0 : j + 1);
1076 i++;
1077 }
1078 *(p->ipos) = (MYFLT) (i - j);
1079
1080 return OK;
1081 }
1082
1083 /**
1084 * ipos strrindex Sstr1, Sstr2
1085 * kpos strrindexk Sstr1, Sstr2
1086 *
1087 * Return the position of the last occurence of Sstr2 in Sstr1,
1088 * or -1 if not found. If Sstr2 is empty, the length of Sstr1 is
1089 * returned.
1090 */
1091
strrindex_opcode(CSOUND * csound,STRINDEX_OP * p)1092 int32_t strrindex_opcode(CSOUND *csound, STRINDEX_OP *p)
1093 {
1094 const char *s1 = (char*) p->Ssrc1->data;
1095 const char *s2 = (char*) p->Ssrc2->data;
1096 int32_t i, j, k;
1097
1098 (void) csound;
1099 /* search substring from left to right, */
1100 /* and return position of last match */
1101 i = j = 0;
1102 k = -1;
1103 while (1) {
1104 if (s2[j] == '\0') {
1105 k = i - j;
1106 j = 0;
1107 }
1108 if (s1[i] == '\0')
1109 break;
1110 j = (s1[i] != s2[j] ? 0 : j + 1);
1111 i++;
1112 }
1113 *(p->ipos) = (MYFLT) k;
1114
1115 return OK;
1116 }
1117
1118 #ifdef HAVE_CURL
str_from_url(CSOUND * csound,STRCPY_OP * p)1119 int32_t str_from_url(CSOUND *csound, STRCPY_OP *p)
1120 {
1121 char *newVal = p->str->data;
1122 if (strstr(newVal, ":/")==NULL) return strcpy_opcode_S(csound, p);
1123 {
1124 CORFIL *mm = copy_url_corefile(csound, newVal,0);
1125 int32_t len = corfile_length(mm);
1126 if (p->r->data == NULL) {
1127 p->r->data = cs_strdup(csound, corfile_body(mm));
1128 p->r->size = len + 1;
1129 goto cleanup;
1130 }
1131 if (UNLIKELY(len >= p->r->size)) {
1132 csound->Free(csound, p->r->data);
1133 p->r->data = cs_strdup(csound, corfile_body(mm));
1134 p->r->size = len + 1;
1135 }
1136 else strcpy((char*) p->r->data, corfile_body(mm));
1137 cleanup:
1138 corfile_rm(csound, &mm);
1139 return OK;
1140 }
1141 }
1142 #endif
1143
1144 #if !defined(HAVE_STRLCAT) && !defined(strlcat) && !defined(EMSCRIPTEN)
1145 /* Direct from BSD sources */
1146 /*
1147 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1148 *
1149 * Permission to use, copy, modify, and distribute this software for any
1150 * purpose with or without fee is hereby granted, provided that the above
1151 * copyright notice and this permission notice appear in all copies.
1152 */
1153 size_t
strlcat(char * dst,const char * src,size_t siz)1154 strlcat(char *dst, const char *src, size_t siz)
1155 {
1156 char *d = dst;
1157 const char *s = src;
1158 size_t n = siz;
1159 size_t dlen;
1160
1161 /* Find the end of dst and adjust bytes left but don't go past end */
1162 while (n-- != 0 && *d != '\0')
1163 d++;
1164 dlen = d - dst;
1165 n = siz - dlen;
1166
1167 if (n == 0)
1168 return (dlen + strlen(s));
1169 while (*s != '\0') {
1170 if (n != 1) {
1171 *d++ = *s;
1172 n--;
1173 }
1174 s++;
1175 }
1176 *d = '\0';
1177
1178 return (dlen + (s - src)); /* count does not include NUL */
1179 }
1180 #endif
1181
1182 /* Modified from BSD sources for strlcpy */
1183 /*
1184 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1185 *
1186 * Permission to use, copy, modify, and distribute this software for any
1187 * purpose with or without fee is hereby granted, provided that the above
1188 * copyright notice and this permission notice appear in all copies.
1189 */
1190 /* modifed for speed -- JPff */
1191 char *
strNcpy(char * dst,const char * src,size_t siz)1192 strNcpy(char *dst, const char *src, size_t siz)
1193 {
1194 char *d = dst;
1195 const char *s = src;
1196 size_t n = siz;
1197
1198 /* Copy as many bytes as will fit or until NULL */
1199 if (n != 0) {
1200 while (--n != 0) {
1201 if ((*d++ = *s++) == '\0')
1202 break;
1203 }
1204 }
1205
1206 /* Not enough room in dst, add NUL */
1207 if (n == 0) {
1208 if (siz != 0)
1209 *d = '\0'; /* NUL-terminate dst */
1210
1211 //while (*s++) ;
1212 }
1213 return dst; /* count does not include NUL */
1214 }
1215
1216 /* Debugging opcode for testing runtime type identification */
print_type_opcode(CSOUND * csound,PRINT_TYPE_OP * p)1217 int32_t print_type_opcode(CSOUND* csound, PRINT_TYPE_OP* p) {
1218 char* ptr = (char*)p->inVar;
1219
1220 CS_TYPE* varType = *(CS_TYPE**)(ptr - CS_VAR_TYPE_OFFSET);
1221 csound->Message(csound, "Variable Type: %s\n", varType->varTypeName);
1222
1223 return OK;
1224 }
1225