1 /*
2 utility.c:
3
4 Copyright (C) 2005 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 <setjmp.h>
26 #include "corfile.h"
27
28 typedef struct csUtility_s {
29 char *name;
30 struct csUtility_s *nxt;
31 int (*UtilFunc)(CSOUND*, int, char**);
32 char *desc;
33 } csUtility_t;
34
csoundAddUtility(CSOUND * csound,const char * name,int (* UtilFunc)(CSOUND *,int,char **))35 int csoundAddUtility(CSOUND *csound, const char *name,
36 int (*UtilFunc)(CSOUND*, int, char**))
37 {
38 csUtility_t *p;
39 /* csound->Message(csound, "csoundAddUtility: name: %s function: 0x%p\n",
40 name, UtilFunc); */
41 if (UNLIKELY(csound == NULL || name == NULL ||
42 name[0] == '\0' || UtilFunc == NULL))
43 return -1;
44 p = (csUtility_t*) csound->utility_db;
45 if (LIKELY(p != NULL)) {
46 do {
47 if (UNLIKELY(strcmp(p->name, name) == 0))
48 return -1; /* name is already in use */
49 if (p->nxt == NULL)
50 break;
51 p = p->nxt;
52 } while (1);
53 p->nxt = csound->Malloc(csound, sizeof(csUtility_t));
54 p = p->nxt;
55 }
56 else {
57 csound->utility_db = csound->Calloc(csound, sizeof(csUtility_t));
58 p = (csUtility_t*) csound->utility_db;
59 }
60 p->name = csound->Malloc(csound, strlen(name) + 1);
61 strcpy(p->name, name);
62 p->nxt = NULL;
63 p->UtilFunc = UtilFunc;
64 p->desc = NULL;
65 return 0;
66 }
67
csoundRunUtility(CSOUND * csound,const char * name,int argc,char ** argv)68 PUBLIC int csoundRunUtility(CSOUND *csound, const char *name,
69 int argc, char **argv)
70 {
71 csUtility_t *p;
72 char **lst;
73 volatile void *saved_exitjmp;
74 volatile int n;
75
76 if (UNLIKELY(csound == NULL))
77 return -1;
78
79 saved_exitjmp = (void*) csound->Malloc(csound, sizeof(jmp_buf));
80 if (UNLIKELY(saved_exitjmp == NULL))
81 return -1;
82 memcpy((void*) saved_exitjmp, (void*) &(csound->exitjmp), sizeof(jmp_buf));
83
84 if (UNLIKELY((n = setjmp(csound->exitjmp)) != 0)) {
85 n = (n - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS;
86 goto err_return;
87 }
88
89 if (UNLIKELY(name == NULL || name[0] == '\0'))
90 goto notFound;
91 p = (csUtility_t*) csound->utility_db;
92 while (1) {
93 if (UNLIKELY(p == NULL))
94 goto notFound;
95 if (strcmp(p->name, name) == 0)
96 break;
97 p = p->nxt;
98 }
99 csound->engineStatus |= CS_STATE_UTIL;
100 csound->scorename = csound->orchname = (char*) name; /* needed ? */
101 csound->Message(csound, Str("util %s:\n"), name);
102 n = p->UtilFunc(csound, argc, argv);
103 goto err_return;
104
105 notFound:
106 if (name != NULL && name[0] != '\0') {
107 print_opcodedir_warning(csound);
108 csound->ErrorMsg(csound, Str("Error: utility '%s' not found"), name);
109 }
110 else
111 csound->ErrorMsg(csound, Str("Error: utility not found"));
112 lst = csound->ListUtilities(csound);
113 if (lst != NULL && lst[0] != NULL) {
114 int i;
115 csound->Message(csound, Str("The available utilities are:\n"));
116 for (i = 0; lst[i] != NULL; i++) {
117 const char *desc = csound->GetUtilityDescription(csound, lst[i]);
118 if (desc != NULL)
119 csound->Message(csound, " %s\t%s\n", lst[i], Str(desc));
120 else
121 csound->Message(csound, " %s\n", lst[i]);
122 }
123 }
124 csoundDeleteUtilityList(csound, lst);
125 n = -1;
126 err_return:
127 memcpy((void*) &(csound->exitjmp), (void*) saved_exitjmp, sizeof(jmp_buf));
128 csound->Free(csound, (void*) saved_exitjmp);
129 return n;
130 }
131
cmp_func(const void * a,const void * b)132 static int cmp_func(const void *a, const void *b)
133 {
134 return strcmp(*((char**) a), *((char**) b));
135 }
136
137 /**
138 * Returns a NULL terminated list of registered utility names.
139 * The caller is responsible for freeing the returned array with
140 * csoundDeleteUtilityList(), however, the names should not be
141 * changed or freed.
142 * The return value may be NULL in case of an error.
143 */
144
csoundListUtilities(CSOUND * csound)145 PUBLIC char **csoundListUtilities(CSOUND *csound)
146 {
147 csUtility_t *p = (csUtility_t*) csound->utility_db;
148 char **lst;
149 int utilCnt = 0;
150
151 /* find out the number of utilities */
152 while (p != NULL)
153 p = p->nxt, utilCnt++;
154 /* allocate list */
155 lst = (char**) csound->Malloc(csound, sizeof(char*) * (utilCnt + 1));
156 if (UNLIKELY(lst == NULL))
157 return NULL;
158 /* store pointers to utility names */
159 utilCnt = 0;
160 p = (csUtility_t*) csound->utility_db;
161 while (p != NULL) {
162 lst[utilCnt++] = (char*) p->name;
163 p = p->nxt;
164 }
165 lst[utilCnt] = NULL;
166 qsort(lst, utilCnt, sizeof(char*), cmp_func);
167 /* return with pointer to list */
168 return lst;
169 }
170
171 /**
172 * Releases an utility list previously returned by csoundListUtilities().
173 */
174
csoundDeleteUtilityList(CSOUND * csound,char ** lst)175 PUBLIC void csoundDeleteUtilityList(CSOUND *csound, char **lst)
176 {
177 if (lst != NULL)
178 csound->Free(csound, lst);
179 }
180
181 /**
182 * Set description text for the specified utility.
183 * Returns zero on success.
184 */
185
csoundSetUtilityDescription(CSOUND * csound,const char * utilName,const char * utilDesc)186 int csoundSetUtilityDescription(CSOUND *csound, const char *utilName,
187 const char *utilDesc)
188 {
189 csUtility_t *p = (csUtility_t*) csound->utility_db;
190 char *desc = NULL;
191
192 /* check for valid parameters */
193 if (UNLIKELY(utilName == NULL))
194 return CSOUND_ERROR;
195 /* find utility in database */
196 while (p != NULL && strcmp(p->name, utilName) != 0)
197 p = p->nxt;
198 if (UNLIKELY(p == NULL))
199 return CSOUND_ERROR; /* not found */
200 /* copy description text */
201 if (utilDesc != NULL && utilDesc[0] != '\0') {
202 desc = (char*) csound->Malloc(csound, strlen(utilDesc) + 1);
203 if (UNLIKELY(desc == NULL))
204 return CSOUND_MEMORY;
205 strcpy(desc, utilDesc);
206 }
207 if (p->desc != NULL)
208 csound->Free(csound, p->desc);
209 p->desc = desc;
210 /* report success */
211 return CSOUND_SUCCESS;
212 }
213
214 /**
215 * Get utility description.
216 * Returns NULL if the utility was not found, or it has no description,
217 * or an error occured.
218 */
219
csoundGetUtilityDescription(CSOUND * csound,const char * utilName)220 PUBLIC const char *csoundGetUtilityDescription(CSOUND *csound,
221 const char *utilName)
222 {
223 csUtility_t *p = (csUtility_t*) csound->utility_db;
224
225 /* check for valid parameters */
226 if (UNLIKELY(utilName == NULL))
227 return NULL;
228 /* find utility in database */
229 while (p != NULL && strcmp(p->name, utilName) != 0)
230 p = p->nxt;
231 if (UNLIKELY(p == NULL))
232 return NULL; /* not found */
233 /* return with utility description (if any) */
234 return (const char*) p->desc;
235 }
236
237 /* ------------------------------------------------------------------------ */
238
239 /**
240 * Sorts score file 'inFile' and writes the result to 'outFile'.
241 * The Csound instance should be initialised with csoundPreCompile()
242 * before calling this function, and csoundReset() should be called
243 * after sorting the score to clean up. On success, zero is returned.
244 */
245
csoundScoreSort(CSOUND * csound,FILE * inFile,FILE * outFile)246 PUBLIC int csoundScoreSort(CSOUND *csound, FILE *inFile, FILE *outFile)
247 {
248 int err;
249 CORFIL *inf = corfile_create_w(csound);
250 int c;
251 if ((err = setjmp(csound->exitjmp)) != 0) {
252 return ((err - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
253 }
254 while ((c=getc(inFile))!=EOF) corfile_putc(csound, c, inf);
255 corfile_puts(csound, "\ne\n#exit\n", inf);
256 corfile_rewind(inf);
257 /* scsortstr() ignores the second arg - Jan 5 2012 */
258 csound->scorestr = inf;
259 scsortstr(csound, inf);
260 while ((c=corfile_getc(csound->scstr))!=EOF)
261 putc(c, outFile);
262 corfile_rm(csound, &csound->scstr);
263 return 0;
264 }
265
266 /**
267 * Extracts from 'inFile', controlled by 'extractFile', and writes
268 * the result to 'outFile'. The Csound instance should be initialised
269 * with csoundPreCompile() before calling this function, and csoundReset()
270 * should be called after score extraction to clean up.
271 * The return value is zero on success.
272 */
csoundScoreExtract(CSOUND * csound,FILE * inFile,FILE * outFile,FILE * extractFile)273 PUBLIC int csoundScoreExtract(CSOUND *csound,
274 FILE *inFile, FILE *outFile, FILE *extractFile)
275 {
276 int err;
277 CORFIL *inf = corfile_create_w(csound);
278 int c;
279 if ((err = setjmp(csound->exitjmp)) != 0) {
280 return ((err - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
281 }
282 while ((c=getc(inFile))!=EOF) corfile_putc(csound, c, inf);
283 corfile_rewind(inf);
284 scxtract(csound, inf, extractFile);
285 while ((c=corfile_getc(csound->scstr))!=EOF)
286 putc(c, outFile);
287 corfile_rm(csound, &csound->scstr);
288 return 0;
289 }
290