1/*
2 * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/**
17 * @file picopal.c
18 *
19 * pico platform abstraction layer
20 *
21 * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
22 * All rights reserved.
23 *
24 * History:
25 * - 2009-04-20 -- initial version
26 *
27 */
28
29/* GCC does not supporte #pragma message */
30#if !defined(__GNUC__)
31#define PRAGMA_MESSAGE
32#endif
33
34#if defined(PRAGMA_MESSAGE) && defined(PICO_PLATFORM)
35#pragma message("PICO_PLATFORM       : is defined externally")
36#endif
37
38#if defined(PRAGMA_MESSAGE) && defined(_WIN32)
39#pragma message("_WIN32              : is defined")
40#endif
41
42#if defined(PRAGMA_MESSAGE) && defined(__APPLE__)
43#pragma message("__APPLE__           : is defined")
44#endif
45
46#if defined(PRAGMA_MESSAGE) && defined(__MACH__)
47#pragma message("__MACH__            : is defined")
48#endif
49
50#if defined(PRAGMA_MESSAGE) && defined(macintosh)
51#pragma message("macintosh           : is defined")
52#endif
53
54#if defined(PRAGMA_MESSAGE) && defined(linux)
55#pragma message("linux               : is defined")
56#endif
57#if defined(PRAGMA_MESSAGE) && defined(__linux__)
58#pragma message("__linux__           : is defined")
59#endif
60#if defined(PRAGMA_MESSAGE) && defined(__linux)
61#pragma message("__linux             : is defined")
62#endif
63
64
65#include <stdlib.h>
66#include <string.h>
67#include <stdio.h>
68#include <stdarg.h>
69
70#include "picodefs.h"
71#include "picopal.h"
72
73#ifdef __cplusplus
74extern "C" {
75#endif
76#if 0
77}
78#endif
79
80#if PICO_PLATFORM == PICO_Windows
81/* use high-resolution timer functions on Windows platform */
82#define USE_CLOCK 0
83#else
84/* use clock() function instead of high-resolution timer on
85   non-Windows platforms */
86#define USE_CLOCK 1
87#endif
88
89#include <time.h>
90#if PICO_PLATFORM == PICO_Windows
91#include <windows.h>
92#endif
93
94#if defined(PRAGMA_MESSAGE)
95#pragma message("PICO_PLATFORM       : " PICO_PLATFORM_STRING)
96#endif
97
98
99picopal_int32 picopal_atoi(const picopal_char *s) {
100  return (picopal_int32)atoi((const char *)s);
101}
102
103picopal_int32 picopal_strcmp(const picopal_char *a, const picopal_char *b) {
104  return (picopal_int32)strcmp((const char *)a, (const char *)b);
105}
106
107picopal_int32 picopal_strncmp(const picopal_char *a, const picopal_char *b, picopal_objsize_t siz) {
108  return (picopal_int32)strncmp((const char *)a, (const char *)b, (size_t) siz);
109}
110
111picopal_objsize_t picopal_strlen(const picopal_char *s) {
112  return (picopal_objsize_t)strlen((const char *)s);
113}
114
115picopal_char *picopal_strchr(const picopal_char *s, picopal_char c) {
116  return (picopal_char *)strchr((const char *)s, (int)c);
117}
118
119picopal_char *picopal_strstr(const picopal_char *s, const picopal_char *substr) {
120  return (picopal_char *)strstr((const char *)s, (const char *)substr);
121}
122
123picopal_char *picopal_strcpy(picopal_char *d, const picopal_char *s) {
124  return (picopal_char *)strcpy((char *)d, (const char *)s);
125}
126
127picopal_char *picopal_strcat(picopal_char *dest, const picopal_char *src) {
128  return (picopal_char *)strcat((char *)dest, (const char *)src);
129}
130
131
132/* copy src into dst, but make sure that dst is not accessed beyond its size 'siz' and is allways NULLC-terminated.
133 * 'siz' is the number of bytes of the destination, including one byte for NULLC!
134 * returns the full length of the input string, not including termination NULLC (strlen(src)).
135 * the copy is successfull without truncation if picopal_strlcpy(dst,src,siz) < siz */
136picopal_objsize_t picopal_strlcpy(picopal_char *dst, const picopal_char *src, picopal_objsize_t siz)
137{
138        picopal_char *d = dst;
139        const picopal_char *s = src;
140        picopal_objsize_t n = siz;
141
142        /* Copy as many bytes as will fit */
143        if (n != 0) {
144                while (--n != 0) {
145                        if ((*(d++) = *(s++)) == NULLC) {
146                                break;
147                        }
148                }
149        }
150
151        /* Not enough room in dst, add NULLC and traverse rest of src */
152        if (n == 0) {
153                if (siz != 0) {
154                        *d = NULLC;                /* NULLC-terminate dst */
155                }
156                while (*(s++)) {}
157                        ;
158        }
159
160        return(s - src - 1);        /* count does not include NULLC */
161}
162
163
164picopal_int16 picopal_sprintf(picopal_char * dst, const picopal_char *fmt, ...)
165{
166    picopal_int16 i;
167    va_list args;
168
169    va_start(args, (char *)fmt);
170    i = (picopal_int16)vsprintf((char *) dst, (const char *)fmt, args);
171    va_end(args);
172    return i;
173}
174
175
176picopal_objsize_t picopal_vslprintf(picopal_char * dst, picopal_objsize_t siz, const picopal_char *fmt, va_list args) {
177    picopal_char buf[21];
178    picopal_char *d = dst;
179    const picopal_char *f = fmt;
180    picopal_char * b;
181    picopal_objsize_t len, nnew, n = siz;
182    picopal_int32 ival;
183    picopal_char cval;
184    picopal_objsize_t i = 0;
185
186    if (!f) {
187        f = (picopal_char *) "";
188    }
189    while (*f) {
190        if (*f == '%') {
191            switch (*(++f)) {
192                case 'i':
193                    f++;
194                    ival = va_arg(args,int);
195                    picopal_sprintf(buf,(picopal_char *)"%i",ival);
196                    b = buf;
197                    break;
198                case 'c':
199                    f++;
200                    cval = va_arg(args,int);
201                    picopal_sprintf(buf,(picopal_char *)"%c",cval);
202                    b = buf;
203                    break;
204                case 's':
205                    f++;
206                    b = (picopal_char *) va_arg(args, char*);
207                    break;
208                default:
209                    if (n > 0) {
210                        (*d++) = '%';
211                        n--;
212                    }
213                    i++;
214                    b = NULL;
215                    break;
216            }
217            if (b) {
218                len = picopal_strlcpy(d,b,n); /* n1 is the actual length of sval */
219                i += len;
220                nnew = (n > len) ? n-len : 0; /* nnew is the new value of n */
221                d += (n - nnew);
222                n = nnew;
223            }
224        } else {
225            if (n) {
226                (*d++) = (*f);
227                n--;
228            }
229            i++;
230            f++;
231        }
232    }
233
234    return i;
235}
236
237picopal_objsize_t picopal_slprintf(picopal_char * dst, picopal_objsize_t siz, const picopal_char *fmt, /*args*/ ...) {
238    picopal_objsize_t i;
239    va_list args;
240
241    va_start(args, (char *)fmt);
242    i = picopal_vslprintf(dst, siz, fmt, args);
243    va_end(args);
244    return i;
245
246}
247
248
249/* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */
250void * picopal_mem_copy(const void * src, void * dst, picopal_objsize_t length)
251{
252    return memmove(dst, src, (size_t) length);
253}
254
255/* sets 'length' bytes starting at dest[0] to 'byte_val' */
256void * picopal_mem_set(void * dest, picopal_uint8 byte_val, picopal_objsize_t length)
257{
258    return memset(dest, (int) byte_val, (size_t) length);
259}
260
261/* *************************************************/
262/* fixed-point math                                */
263/* *************************************************/
264
265/* *************************************************/
266/* transcendent math                                */
267/* *************************************************/
268
269
270picopal_double picopal_cos(const picopal_double cos_arg)
271{
272    return (picopal_double) cos((double)cos_arg);
273}
274picopal_double picopal_sin(const picopal_double sin_arg)
275{
276    return (picopal_double) sin((double) sin_arg);
277}
278picopal_double picopal_fabs(const picopal_double fabs_arg)
279{
280    return (picopal_double) fabs((double) fabs_arg);
281}
282
283
284/* *************************************************/
285/* file access                                     */
286/* *************************************************/
287#define PICOPAL_EOL '\n'
288
289picopal_char picopal_eol(void)
290{
291    return PICOPAL_EOL;
292}
293
294/* 'fopen' opens the file with name 'filename'. Depending on
295   'mode' :
296      'PICOPAL_TEXT_READ'    : Opens an existing text file for reading.
297                      The file is positioned at the beginning of the file.
298      'PICOPAL_TEXT_WRITE'   : Opens and truncates an existing file or creates a new
299                      text file for writing. The file is positioned at the
300                      beginning.
301      'PICOPAL_BIN_READ'  : Opens an existing binary file for reading.
302                      The file is positioned at the beginning of the file.
303      'PICOPAL_BIN_WRITE' : Opens and truncates an existing file or creates a new
304                      binary file for writing. The file is positioned at the
305                      beginning.
306    If the opening of the file is successful a file pointer is given
307    back. Otherwise a NIL-File is given back.
308*/
309picopal_File picopal_fopen (picopal_char filename[], picopal_access_mode mode)
310{
311    picopal_File res;
312
313     switch (mode) {
314     case PICOPAL_TEXT_READ :
315         res = (picopal_File) fopen((char *)filename, (char *)"r");
316         break;
317     case PICOPAL_TEXT_WRITE :
318         res = (picopal_File) fopen((char *)filename, (char *)"w");
319         break;
320     case PICOPAL_BINARY_READ :
321         res = (picopal_File) fopen((char *)filename, (char *)"rb");
322         break;
323     case PICOPAL_BINARY_WRITE :
324         res = (picopal_File) fopen((char *)filename, (char *)"wb");
325         break;
326     default :
327         res = (picopal_File) NULL;
328     }
329     return res;
330
331}
332
333
334picopal_File picopal_get_fnil (void)
335{
336    return (picopal_File) NULL;
337}
338
339
340picopal_int8 picopal_is_fnil (picopal_File f)
341{
342    return (NULL == f);
343}
344
345pico_status_t picopal_fflush (picopal_File f)
346{
347    return (0 == fflush((FILE *)f)) ? PICO_OK : PICO_EOF;
348}
349
350
351pico_status_t picopal_fclose (picopal_File f)
352{
353    return (0 == fclose((FILE *)f)) ? PICO_OK : PICO_EOF;
354}
355
356
357
358picopal_uint32 picopal_flength (picopal_File stream)
359{
360    fpos_t fpos;
361    picopal_int32 len;
362
363    fgetpos((FILE *)stream,&fpos);
364    picopal_fseek(stream,0,SEEK_END);
365    len = ftell((FILE *)stream);
366    fsetpos((FILE *)stream,&fpos);
367    clearerr((FILE *)stream);
368    return len;
369
370}
371
372picopal_uint8 picopal_feof (picopal_File stream)
373{
374    return (0 != feof((FILE *)stream));
375
376}
377
378pico_status_t picopal_fseek (picopal_File f, picopal_uint32 offset, picopal_int8 seekmode)
379{
380    return (0 == fseek((FILE *)f, offset, seekmode)) ? PICO_OK : PICO_EOF;
381}
382
383pico_status_t picopal_fget_char (picopal_File f, picopal_char * ch)
384{
385    picopal_int16 res;
386
387    res = fgetc((FILE *)f);
388    if (res >= 0) {
389      *ch = (picopal_char) res;
390    }
391    else {
392      *ch = '\0';
393    }
394    return (res >= 0) ? PICO_OK : PICO_EOF;
395}
396
397picopal_objsize_t picopal_fread_bytes (picopal_File f, void * ptr, picopal_objsize_t objsize, picopal_uint32 nobj)
398{
399    return (picopal_objsize_t) fread(ptr, objsize, nobj, (FILE *)f);
400}
401
402picopal_objsize_t picopal_fwrite_bytes (picopal_File f, void * ptr, picopal_objsize_t objsize, picopal_uint32 nobj){    return (picopal_objsize_t) fwrite(ptr, objsize, nobj, (FILE *)f);}
403/* *************************************************/
404/* functions for debugging/testing purposes only   */
405/* *************************************************/
406
407void *picopal_mpr_alloc(picopal_objsize_t size)
408{
409#if PICO_PLATFORM == PICO_Windows
410    return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
411#else
412    /* not yet implemented for other platforms;  corresponding
413       function on UNIX systems is pvalloc */
414    return NULL;
415#endif
416    size = size;        /* avoid warning "var not used in this function"*/
417
418}
419
420void picopal_mpr_free(void **p)
421{
422#if PICO_PLATFORM == PICO_Windows
423    VirtualFree(*p, 0, MEM_RELEASE);
424#else
425    /* not yet implemented for other platforms */
426#endif
427    *p = NULL;
428}
429
430pico_status_t picopal_mpr_protect(void *addr, picopal_objsize_t len, picopal_int16 prot)
431{
432    pico_status_t status = PICO_OK;
433
434#if PICO_PLATFORM == PICO_Windows
435    DWORD dwNewProtect, dwOldProtect;
436    dwNewProtect = PICOPAL_PROT_NONE;
437    if (prot & PICOPAL_PROT_READ) {
438        if (prot & PICOPAL_PROT_WRITE) {
439            dwNewProtect = PAGE_READWRITE;
440        } else {
441            dwNewProtect = PAGE_READONLY;
442        }
443    } else if (prot & PICOPAL_PROT_WRITE) {
444        /* under Windows write-only is not possible */
445        dwNewProtect = PAGE_READWRITE;
446    }
447    if (!VirtualProtect(addr, len, dwNewProtect, &dwOldProtect)) {
448        status = PICO_ERR_OTHER;
449    }
450#else
451    /* not yet implemented for other platforms */
452    addr = addr;        /* avoid warning "var not used in this function"*/
453    len = len;            /* avoid warning "var not used in this function"*/
454    prot = prot;        /* avoid warning "var not used in this function"*/
455
456#endif
457    return status;
458}
459/*
460 *  Reference:
461 * A Fast, Compact Approximation of the Exponential Function by Nicol N. Schraudolph in Neural Computation, 11,853-862 (1999)
462 * See also: http://www-h.eng.cam.ac.uk/help/tpl/programs/Matlab/mex.html
463 *
464 */
465picopal_double picopal_quick_exp(const picopal_double y) {
466    union {
467        picopal_double d;
468          struct {
469            #if PICO_ENDIANNESS == ENDIANNESS_LITTLE /* little endian */
470              picopal_int32 j,i;
471            #else
472              picopal_int32 i,j;
473            #endif
474          } n;
475
476    } _eco;
477    _eco.n.i = (picopal_int32)(1512775.3951951856938297995605697f * y) + 1072632447;
478    return _eco.d;
479}
480
481
482/* *************************************************/
483/* timer                                           */
484/* *************************************************/
485
486#if IMPLEMENT_TIMER
487
488#define USEC_PER_SEC 1000000
489
490typedef clock_t picopal_clock_t;
491
492
493#if USE_CLOCK
494picopal_clock_t startTime;
495#else
496int timerInit = 0;
497LARGE_INTEGER startTime;
498LARGE_INTEGER timerFreq;
499#endif
500
501
502picopal_clock_t picopal_clock(void)
503{
504    return (picopal_clock_t)clock();
505}
506
507#endif /* IMPLEMENT_TIMER */
508
509void picopal_get_timer(picopal_uint32 * sec, picopal_uint32 * usec)
510{
511#if IMPLEMENT_TIMER
512#if USE_CLOCK
513    picopal_clock_t dt;
514    dt = picopal_clock() - startTime;
515    *sec = dt / CLOCKS_PER_SEC;
516    *usec = USEC_PER_SEC * (dt % CLOCKS_PER_SEC) / CLOCKS_PER_SEC;
517#else
518    LARGE_INTEGER now;
519    if (!timerInit) {
520      QueryPerformanceFrequency(&timerFreq);
521      timerInit = 1;
522    }
523    if (QueryPerformanceCounter(&now) && 0) {
524/*
525        LONGLONG dt, tf;
526        dt = now.QuadPart - GLOB(startTime).QuadPart;
527        tf = GLOB(timerFreq).QuadPart;
528        *sec = (unsigned int) (dt / tf);
529        *usec = (unsigned int) (USEC_PER_SEC * (dt % tf) / tf);
530*/
531        double dt, tf;
532        dt = (double)(now.QuadPart - startTime.QuadPart);
533        tf = (double)(timerFreq.QuadPart);
534        *sec = (unsigned int) (dt /tf);
535        *usec = (unsigned int) ((double)USEC_PER_SEC * (dt / tf)) % USEC_PER_SEC;
536    } else {
537        /* high freq counter not supported by system */
538        DWORD dt;
539        dt = GetTickCount() - startTime.LowPart;
540        *sec = dt / 1000;
541        *usec = 1000 * (dt % 1000);
542    }
543#endif /* USE_CLOCK */
544#else
545    *sec = 0;
546    *usec = 0;
547#endif /* IMPLEMENT_TIMER */
548}
549
550#ifdef __cplusplus
551}
552#endif
553
554/* End picopal.c */
555