1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
14 #include "sjme/config.h"
16 #if defined(SJME_CONFIG_HAS_LINUX) || \
17 defined(SJME_CONFIG_HAS_BSD)
18 #define SJME_CONFIG_POSIX_CLOCK_GET_TIME
21 #if defined(SJME_CONFIG_HAS_WINDOWS)
22 #define WIN32_LEAN_AND_MEAN 1
26 #undef WIN32_LEAN_AND_MEAN
27 #elif defined(SJME_CONFIG_POSIX_CLOCK_GET_TIME)
32 #include "sjme/native.h"
35 static sjme_errorCode
sjme_nal_default_cFileClose(
36 sjme_attrInNotNull sjme_seekable inSeekable
,
37 sjme_attrInNotNull sjme_seekable_implState
* inImplState
)
41 if (inSeekable
== NULL
|| inImplState
== NULL
)
42 return SJME_ERROR_NULL_ARGUMENTS
;
44 /* Recover file handle. */
45 file
= inSeekable
->implState
.handle
;
48 if (0 != fclose(file
))
49 return sjme_nal_errno(errno
);
52 return SJME_ERROR_NONE
;
55 static sjme_errorCode
sjme_nal_default_cFileInit(
56 sjme_attrInNotNull sjme_seekable inSeekable
,
57 sjme_attrInNotNull sjme_seekable_implState
* inImplState
,
58 sjme_attrInNullable sjme_pointer data
)
60 if (inSeekable
== NULL
|| inImplState
== NULL
|| data
== NULL
)
61 return SJME_ERROR_NULL_ARGUMENTS
;
63 /* We can just set the file handle here. */
64 inImplState
->handle
= data
;
67 return SJME_ERROR_NONE
;
70 static sjme_errorCode
sjme_nal_default_cFileRead(
71 sjme_attrInNotNull sjme_seekable inSeekable
,
72 sjme_attrInNotNull sjme_seekable_implState
* inImplState
,
73 sjme_attrOutNotNullBuf(length
) sjme_buffer outBuf
,
74 sjme_attrInPositive sjme_jint base
,
75 sjme_attrInPositiveNonZero sjme_jint length
)
78 sjme_jint left
, destAt
, rc
;
80 if (inSeekable
== NULL
|| inImplState
== NULL
|| outBuf
== NULL
)
81 return SJME_ERROR_NULL_ARGUMENTS
;
83 /* Recover file handle. */
84 file
= inSeekable
->implState
.handle
;
86 /* Seek to read position. */
87 if (fseek(file
, base
, SEEK_SET
))
88 return sjme_nal_errno(errno
);
90 /* Make sure it is a valid position. */
92 return sjme_nal_errno(errno
);
94 /* fread() can result in short reads, so read everything fully. */
100 rc
= fread(SJME_POINTER_OFFSET(outBuf
, destAt
),
103 /* These should never happen. */
104 if (feof(file
) || ferror(file
))
105 return sjme_nal_errno(errno
);
113 return SJME_ERROR_NONE
;
116 static sjme_errorCode
sjme_nal_default_cFileSize(
117 sjme_attrInNotNull sjme_seekable inSeekable
,
118 sjme_attrInNotNull sjme_seekable_implState
* inImplState
,
119 sjme_attrOutNotNull sjme_jint
* outSize
)
124 if (inSeekable
== NULL
|| inImplState
== NULL
|| outSize
== NULL
)
125 return SJME_ERROR_NULL_ARGUMENTS
;
127 /* Recover file handle. */
128 file
= inSeekable
->implState
.handle
;
131 if (fseek(file
, 0, SEEK_END
) < 0)
132 return sjme_nal_errno(errno
);
134 /* File size is the given position. */
135 result
= ftell(file
);
137 return sjme_nal_errno(errno
);
141 return SJME_ERROR_NONE
;
144 /** Functions for C File access. */
145 static const sjme_seekable_functions sjme_nal_default_cFileFunctions
=
147 .close
= sjme_nal_default_cFileClose
,
148 .init
= sjme_nal_default_cFileInit
,
149 .read
= sjme_nal_default_cFileRead
,
150 .size
= sjme_nal_default_cFileSize
,
153 static sjme_errorCode
sjme_nal_default_fileOpen(
154 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
155 sjme_attrInNotNull sjme_lpcstr inPath
,
156 sjme_attrOutNotNull sjme_seekable
* outSeekable
)
158 sjme_errorCode error
;
160 sjme_seekable result
;
162 if (inPool
== NULL
|| inPath
== NULL
|| outSeekable
== NULL
)
163 return SJME_ERROR_NULL_ARGUMENTS
;
166 cFile
= fopen(inPath
, "rb");
168 return sjme_nal_errno(errno
);
172 if (sjme_error_is(error
= sjme_seekable_open(inPool
,
173 &result
, &sjme_nal_default_cFileFunctions
,
174 cFile
, NULL
)) || result
== NULL
)
176 /* Close before we fail. */
180 return sjme_error_default(error
);
184 *outSeekable
= result
;
185 return SJME_ERROR_NONE
;
188 static sjme_errorCode
sjme_nal_default_getEnv(
189 sjme_attrInNotNull
sjme_attrOutNotNullBuf(len
) sjme_lpstr buf
,
190 sjme_attrInPositiveNonZero sjme_jint bufLen
,
191 sjme_attrInNotNull sjme_lpcstr env
)
196 if (buf
== NULL
|| env
== NULL
)
197 return SJME_ERROR_NULL_ARGUMENTS
;
200 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
205 /* If missing, fail. */
207 return SJME_ERROR_NO_SUCH_ELEMENT
;
211 if (len
< 0 || len
+ 1 > bufLen
)
212 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
215 memmove(buf
, value
, sizeof(*buf
) * (len
+ 1));
216 return SJME_ERROR_NONE
;
219 static sjme_errorCode
sjme_nal_default_nanoTime(
220 sjme_attrOutNotNull sjme_jlong
* result
)
222 #if defined(SJME_CONFIG_HAS_WINDOWS)
225 #elif defined(SJME_CONFIG_POSIX_CLOCK_GET_TIME)
226 struct timespec spec
;
230 return SJME_ERROR_NULL_ARGUMENTS
;
232 #if defined(SJME_CONFIG_HAS_WINDOWS)
233 /* Get frequency of the clock. */
234 memset(&freq
, 0, sizeof(freq
));
235 if (!QueryPerformanceFrequency(&freq
))
236 return SJME_ERROR_NATIVE_SYSTEM_CLOCK_FAILURE
;
238 /* Get actual counter. */
239 memset(&ticks
, 0, sizeof(ticks
));
240 if (!QueryPerformanceCounter(&ticks
))
241 return SJME_ERROR_NATIVE_SYSTEM_CLOCK_FAILURE
;
243 /* Calculate time. */
244 /* Freq: A pointer to a variable that receives the current */
245 /* performance-counter frequency, in counts per second. */
246 result
->full
= (ticks
.QuadPart
/ (freq
.QuadPart
* UINT64_C(1000000000)) /
247 UINT64_C(1000000000));
248 return SJME_ERROR_NONE
;
249 #elif defined(SJME_CONFIG_POSIX_CLOCK_GET_TIME)
250 /* Get system native clock. */
251 memset(&spec
, 0, sizeof(spec
));
252 if (clock_gettime(CLOCK_MONOTONIC
, &spec
) != 0)
253 return SJME_ERROR_NATIVE_SYSTEM_CLOCK_FAILURE
;
255 /* Translate time. */
256 result
->full
= spec
.tv_nsec
+ (spec
.tv_sec
* UINT64_C(1000000000));
257 return SJME_ERROR_NONE
;
259 return SJME_ERROR_NOT_IMPLEMENTED
;
263 static sjme_errorCode
sjme_nal_default_stdErrF(
264 sjme_attrInNotNull sjme_lpcstr format
,
268 sjme_errorCode error
;
270 /* Start argument parsing. */
271 va_start(list
, format
);
273 /* Print directly to formatted output. */
274 error
= SJME_ERROR_NONE
;
275 if (vfprintf(stderr
, format
, list
) < 0)
276 error
= SJME_ERROR_IO_EXCEPTION
;
277 if (EOF
== fflush(stderr
))
278 error
= SJME_ERROR_IO_EXCEPTION
;
280 /* End argument parsing. */
287 static sjme_errorCode
sjme_nal_default_stdOutF(
288 sjme_attrInNotNull sjme_lpcstr format
,
292 sjme_errorCode error
;
294 /* Start argument parsing. */
295 va_start(list
, format
);
297 /* Print directly to formatted output. */
298 error
= SJME_ERROR_NONE
;
299 if (vfprintf(stdout
, format
, list
) < 0)
300 error
= SJME_ERROR_IO_EXCEPTION
;
301 if (EOF
== fflush(stdout
))
302 error
= SJME_ERROR_IO_EXCEPTION
;
304 /* End argument parsing. */
311 const sjme_nal sjme_nal_default
=
313 .currentTimeMillis
= NULL
,
314 .fileOpen
= sjme_nal_default_fileOpen
,
315 .getEnv
= sjme_nal_default_getEnv
,
316 .nanoTime
= sjme_nal_default_nanoTime
,
317 .stdErrF
= sjme_nal_default_stdErrF
,
318 .stdOutF
= sjme_nal_default_stdOutF
,
321 sjme_errorCode
sjme_nal_errno(sjme_jint errNum
)
326 return SJME_ERROR_IO_EXCEPTION
;
329 return SJME_ERROR_FILE_NOT_FOUND
;
332 return SJME_ERROR_UNKNOWN
;