1 /*
2 corfiles.c:
3
4 Copyright (C) 2011 John ffitch
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" /* CORFILES.C */
25 #include <string.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29
30
31 extern int csoundFileClose(CSOUND*, void*);
32 CORFIL *copy_url_corefile(CSOUND *, const char *, int);
33
corfile_create_w(CSOUND * csound)34 CORFIL *corfile_create_w(CSOUND *csound)
35 {
36 CORFIL *ans = (CORFIL*) csound->Malloc(csound, sizeof(CORFIL));
37 ans->body = (char*)csound->Calloc(csound,100); /* 100 is just a number */
38 ans->len = 100;
39 ans->p = 0;
40 return ans;
41 }
42
corfile_create_r(CSOUND * csound,const char * text)43 CORFIL *corfile_create_r(CSOUND *csound, const char *text)
44 {
45 //char *strdup(const char *);
46 CORFIL *ans = (CORFIL*) csound->Malloc(csound, sizeof(CORFIL));
47 ans->body = cs_strdup(csound, (char*)text);
48 ans->len = strlen(text)+1;
49 ans->p = 0;
50 return ans;
51 }
52
corfile_putc(CSOUND * csound,int c,CORFIL * f)53 void corfile_putc(CSOUND *csound, int c, CORFIL *f)
54 {
55 f->body[f->p++] = c;
56 if (UNLIKELY(f->p >= f->len)) {
57 char *new = (char*) csound->ReAlloc(csound, f->body, f->len+=100);
58 if (UNLIKELY(new==NULL)) {
59 fprintf(stderr, Str("Out of Memory\n"));
60 exit(7);
61 }
62 f->body = new;
63 }
64 f->body[f->p] = '\0';
65 }
66
corfile_puts(CSOUND * csound,const char * s,CORFIL * f)67 void corfile_puts(CSOUND *csound, const char *s, CORFIL *f)
68 {
69 const char *c;
70 int n;
71 /* skip and count the NUL chars to the end */
72 for (n=0; f->p > 0 && f->body[f->p-1] == '\0'; n++, f->p--);
73 /* append the string */
74 for (c = s; *c != '\0'; c++) {
75 f->body[f->p++] = *c;
76 if (UNLIKELY(f->p >= f->len)) {
77 char *new = (char*) csound->ReAlloc(csound, f->body, f->len+=100);
78 if (UNLIKELY(new==NULL)) {
79 fprintf(stderr, Str("Out of Memory\n"));
80 exit(7);
81 }
82 f->body = new;
83 }
84 }
85 if (n > 0) {
86 /* put the extra NULL chars to the end */
87 while (--n >= 0) {
88 f->body[f->p++] = '\0';
89 if (UNLIKELY(f->p >= f->len)) {
90 char *new = (char*) csound->ReAlloc(csound, f->body, f->len+=100);
91 if (UNLIKELY(new==NULL)) {
92 fprintf(stderr, Str("Out of Memory\n"));
93 exit(7);
94 }
95 f->body = new;
96 }
97 }
98 }
99 f->body[f->p] = '\0';
100 }
101
corfile_flush(CSOUND * csound,CORFIL * f)102 void corfile_flush(CSOUND *csound, CORFIL *f)
103 {
104 char *new;
105 f->len = strlen(f->body)+1;
106 new = (char*)csound->ReAlloc(csound, f->body, f->len);
107 if (UNLIKELY(new==NULL)) {
108 fprintf(stderr, Str("Out of Memory\n"));
109 exit(7);
110 }
111 f->body = new;
112 f->p = 0;
113 }
114
115 #undef corfile_length
corfile_length(CORFIL * f)116 int corfile_length(CORFIL *f)
117 {
118 return strlen(f->body);
119 }
120
corfile_rm(CSOUND * csound,CORFIL ** ff)121 void corfile_rm(CSOUND *csound, CORFIL **ff)
122 {
123 CORFIL *f = *ff;
124 if (LIKELY(f!=NULL)) {
125 csound->Free(csound, f->body);
126 csound->Free(csound, f);
127 *ff = NULL;
128 }
129 }
130
corfile_getc(CORFIL * f)131 int corfile_getc(CORFIL *f)
132 {
133 int c = f->body[f->p];
134 if (UNLIKELY(c=='\0')) return EOF;
135 f->p++;
136 return c;
137 }
138
corfile_fgets(char * buff,int len,CORFIL * f)139 char *corfile_fgets(char *buff, int len, CORFIL *f)
140 {
141 int i;
142 char *p = &(f->body[f->p]), *q;
143 if (UNLIKELY(*p == '\0')) return NULL;
144 q = strchr(p, '\n');
145 i = (q-p);
146 if (UNLIKELY(i>=len)) i = len-1;
147 memcpy(buff, p, i);
148 f->p += i;
149 return buff;
150 }
151
152 #undef corfile_ungetc
corfile_ungetc(CORFIL * f)153 void corfile_ungetc(CORFIL *f)
154 {
155 --f->p;
156 }
157
corfile_get_flt(CORFIL * f)158 MYFLT corfile_get_flt(CORFIL *f)
159 {
160 int n = f->p;
161 MYFLT ans;
162 while (!isspace(f->body[++f->p]));
163 ans = (MYFLT) atof(&f->body[n]);
164 return ans;
165 }
166
167 #undef corfile_rewind
corfile_rewind(CORFIL * f)168 void corfile_rewind(CORFIL *f)
169 {
170 f->p = 0;
171 }
172
173 #undef corfile_reset
corfile_reset(CORFIL * f)174 void corfile_reset(CORFIL *f)
175 {
176 f->p = 0;
177 f->body[0] = '\0';
178 }
179
180 #undef corfile_tell
corfile_tell(CORFIL * f)181 int corfile_tell(CORFIL *f)
182 {
183 return f->p;
184 }
185
186 #undef corfile_set
corfile_set(CORFIL * f,int n)187 void corfile_set(CORFIL *f, int n)
188 {
189 f->p = n;
190 }
191
corfile_seek(CORFIL * f,int n,int dir)192 void corfile_seek(CORFIL *f, int n, int dir)
193 {
194 if (dir == SEEK_SET) f->p = n;
195 else if (dir == SEEK_CUR) f->p += n;
196 else if (dir == SEEK_END) f->p = strlen(f->body)-n;
197 if (UNLIKELY(f->p > strlen(f->body))) {
198 printf("INTERNAL ERROR: Corfile seek out of range\n");
199 exit(1);
200 }
201 }
202
203
204 #undef corfile_body
corfile_body(CORFIL * f)205 char *corfile_body(CORFIL *f)
206 {
207 return f->body;
208 }
209
210 #undef corfile_current
corfile_current(CORFIL * f)211 char *corfile_current(CORFIL *f)
212 {
213 return f->body+f->p;
214 }
215
216 /* *** THIS NEEDS TO TAKE ACCOUNT OF SEARCH PATH *** */
217 void *fopen_path(CSOUND *csound, FILE **fp, const char *name,
218 const char *basename, char *env, int fromScore);
copy_to_corefile(CSOUND * csound,const char * fname,const char * env,int fromScore)219 CORFIL *copy_to_corefile(CSOUND *csound, const char *fname,
220 const char *env, int fromScore)
221 {
222 CORFIL *mm;
223 FILE *ff;
224 void *fd;
225 int n;
226 char buffer[1024];
227 if (UNLIKELY(fname==NULL)) {
228 csound->ErrorMsg(csound, Str("Null file name in copy_to_corefile"));
229 csound->LongJmp(csound, 1);
230 }
231 #ifdef HAVE_CURL
232 if (strstr(fname,"://")) {
233 /* **** Note the +2 is to skip spurous ./ inserted in a file name */
234 return copy_url_corefile(csound, fname+2, fromScore);
235 }
236 #endif
237 fd = fopen_path(csound, &ff, (char *)fname, NULL, (char *)env, fromScore);
238 if (UNLIKELY(ff==NULL)) return NULL;
239 mm = corfile_create_w(csound);
240 if (fromScore) corfile_putc(csound, '\n', mm);
241 memset(buffer, '\0', 1024);
242 while ((n = fread(buffer, 1, 1023, ff))) {
243 /* Need to lose \r characters here */
244 /* while ((s = strchr(buffer, '\r'))) { */
245 /* int k = n - (s-buffer); */
246 /* memmove(s, s+1, k); */
247 /* n--; */
248 /* } */
249 corfile_puts(csound, buffer, mm);
250 memset(buffer, '\0', 1024);
251 }
252 //#ifdef SCORE_PARSER
253 if (fromScore) {
254 corfile_puts(csound, "\ne\n#exit\n", mm);
255 }
256 //#endif
257 corfile_putc(csound, '\0', mm); /* For use in bison/flex */
258 corfile_putc(csound, '\0', mm); /* For use in bison/flex */
259 if (fromScore) corfile_flush(csound, mm);
260 csoundFileClose(csound, fd);
261 //if (fromScore) printf("Copy is >>%s<<\n", mm->body);
262 return mm;
263 }
264
corfile_preputs(CSOUND * csound,const char * s,CORFIL * f)265 void corfile_preputs(CSOUND *csound, const char *s, CORFIL *f)
266 {
267 char *body = f->body;
268 f->body = (char*)csound->Malloc(csound, f->len=(strlen(body)+strlen(s)+1));
269 f->p = f->len-1;
270 strcpy(f->body, s); strcat(f->body, body);
271 csound->Free(csound, body);
272 }
273
274 #ifdef HAVE_CURL
275
276 #include <curl/curl.h>
277
278 struct MemoryStruct {
279 char *memory;
280 size_t size;
281 CSOUND* cs;
282 };
283
284
285 static size_t
WriteMemoryCallback(void * contents,size_t size,size_t nmemb,void * userp)286 WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
287 {
288 size_t realsize = size * nmemb;
289 struct MemoryStruct *mem = (struct MemoryStruct *)userp;
290 CSOUND *csound = mem->cs;
291
292 mem->memory = csound->ReAlloc(csound, mem->memory, mem->size + realsize + 1);
293 if (UNLIKELY(mem->memory == NULL)) {
294 /* out of memory! */
295 printf(Str("not enough memory (realloc returned NULL)\n"));
296 return 0;
297 }
298
299 memcpy(&(mem->memory[mem->size]), contents, realsize);
300 mem->size += realsize;
301 mem->memory[mem->size] = 0;
302
303 return realsize;
304 }
305
copy_url_corefile(CSOUND * csound,const char * url,int fromScore)306 CORFIL *copy_url_corefile(CSOUND *csound, const char *url, int fromScore)
307 {
308 int n;
309 CURL *curl = curl_easy_init();
310 CORFIL *mm = corfile_create_w(csound);
311 struct MemoryStruct chunk;
312
313 chunk.memory = csound->Malloc(csound, 1); /* will grown */
314 chunk.size = 0; /* no data at this point */
315 chunk.cs = csound;
316 curl_easy_setopt(curl, CURLOPT_URL, url);
317 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
318 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
319 curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
320 n = curl_easy_perform(curl);
321 if (UNLIKELY(n != CURLE_OK)) {
322 csound->Die(csound, Str("curl_easy_perform() failed: %s\n"),
323 curl_easy_strerror(n));
324 /* return NULL ? */
325 }
326 curl_easy_cleanup(curl);
327 corfile_puts(csound, chunk.memory, mm);
328 corfile_putc(csound, '\0', mm); /* For use in bison/flex */
329 corfile_putc(csound, '\0', mm); /* For use in bison/flex */
330 if (fromScore) corfile_flush(csound, mm);
331 csound->Free(csound, chunk.memory);
332
333 curl_global_cleanup();
334 return mm;
335 }
336
337 #endif
338
339 #if 0
340 int main(void)
341 {
342 CURL *curl_handle;
343 CURLcode res;
344
345 struct MemoryStruct chunk;
346
347 /* will grown as needed by the realloc above */
348 chunk.memory = csound->Malloc(csound, 1);
349 chunk.size = 0; /* no data at this point */
350
351 curl_global_init(CURL_GLOBAL_ALL);
352
353 /* init the curl session */
354 curl_handle = curl_easy_init();
355
356 /* specify URL to get */
357 curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.example.com/");
358
359 /* send all data to this function */
360 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
361
362 /* we pass our 'chunk' struct to the callback function */
363 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
364
365 /* some servers don't like requests that are made without a user-agent
366 field, so we provide one */
367 curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
368
369 /* get it! */
370 res = curl_easy_perform(curl_handle);
371
372 /* check for errors */
373 if (res != CURLE_OK) {
374 fprintf(stderr, "curl_easy_perform() failed: %s\n",
375 curl_easy_strerror(res));
376 }
377 else {
378 /*
379 * Now, our chunk.memory points to a memory block that is chunk.size
380 * bytes big and contains the remote file.
381 *
382 * Do something nice with it!
383 */
384
385 printf("%lu bytes retrieved\n", (long)chunk.size);
386 }
387
388 /* cleanup curl stuff */
389 curl_easy_cleanup(curl_handle);
390
391 if (chunk.memory)
392 free(chunk.memory);
393
394 /* we're done with libcurl, so clean it up */
395 curl_global_cleanup();
396
397 return 0;
398 }
399 #endif
400
401 #ifdef JPFF
402 /* Start of directory of corfiles currently unused except experimental in CsFileC */
403 typedef struct dir {
404 char *name;
405 CORFIL *corfile;
406 struct dir *next;
407 } CORDIR;
408
add_corfile(CSOUND * csound,CORFIL * smpf,char * filename)409 void add_corfile(CSOUND* csound, CORFIL *smpf, char *filename)
410 {
411 CORDIR *entry = csound->Malloc(csound, sizeof(CORDIR));
412 entry->name = cs_strdup(csound, filename);
413 entry->corfile = smpf;
414 entry->next = (CORDIR *)csound->directory;
415 csound->directory = entry;
416 }
417 #endif
418