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