Partial buffer slicing.
[SquirrelJME.git] / nanocoat / lib / base / native.c
blob88301dc6669773efb731063affad1d3f8e8c533a
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
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 // -------------------------------------------------------------------------*/
10 #include <stdarg.h>
11 #include <string.h>
12 #include <stdio.h>
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
19 #endif
21 #if defined(SJME_CONFIG_HAS_WINDOWS)
22 #define WIN32_LEAN_AND_MEAN 1
24 #include <windows.h>
26 #undef WIN32_LEAN_AND_MEAN
27 #elif defined(SJME_CONFIG_POSIX_CLOCK_GET_TIME)
28 #include <time.h>
29 #else
30 #endif
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)
39 FILE* file;
41 if (inSeekable == NULL || inImplState == NULL)
42 return SJME_ERROR_NULL_ARGUMENTS;
44 /* Recover file handle. */
45 file = inSeekable->implState.handle;
47 /* Close the file. */
48 if (0 != fclose(file))
49 return sjme_nal_errno(errno);
51 /* Success! */
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;
66 /* Success! */
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)
77 FILE* file;
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. */
91 if (ftell(file) < 0)
92 return sjme_nal_errno(errno);
94 /* fread() can result in short reads, so read everything fully. */
95 destAt = 0;
96 left = length;
97 while (left > 0)
99 /* Read chunk. */
100 rc = fread(SJME_POINTER_OFFSET(outBuf, destAt),
101 1, left, file);
103 /* These should never happen. */
104 if (feof(file) || ferror(file))
105 return sjme_nal_errno(errno);
107 /* Move shift up. */
108 destAt += rc;
109 left -= rc;
112 /* Success! */
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)
121 FILE* file;
122 sjme_jint result;
124 if (inSeekable == NULL || inImplState == NULL || outSize == NULL)
125 return SJME_ERROR_NULL_ARGUMENTS;
127 /* Recover file handle. */
128 file = inSeekable->implState.handle;
130 /* Seek to end. */
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);
136 if (result < 0)
137 return sjme_nal_errno(errno);
139 /* Success! */
140 *outSize = result;
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;
159 FILE* cFile;
160 sjme_seekable result;
162 if (inPool == NULL || inPath == NULL || outSeekable == NULL)
163 return SJME_ERROR_NULL_ARGUMENTS;
165 /* Open file. */
166 cFile = fopen(inPath, "rb");
167 if (cFile == NULL)
168 return sjme_nal_errno(errno);
170 /* Setup stream. */
171 result = NULL;
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. */
177 fclose(cFile);
179 /* Fail. */
180 return sjme_error_default(error);
183 /* Success! */
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)
193 sjme_lpcstr value;
194 sjme_jint len;
196 if (buf == NULL || env == NULL)
197 return SJME_ERROR_NULL_ARGUMENTS;
199 if (bufLen <= 0)
200 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
202 /* Get value. */
203 value = getenv(env);
205 /* If missing, fail. */
206 if (value == NULL)
207 return SJME_ERROR_NO_SUCH_ELEMENT;
209 /* Check bounds. */
210 len = strlen(value);
211 if (len < 0 || len + 1 > bufLen)
212 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
214 /* Copy over. */
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)
223 LARGE_INTEGER freq;
224 LARGE_INTEGER ticks;
225 #elif defined(SJME_CONFIG_POSIX_CLOCK_GET_TIME)
226 struct timespec spec;
227 #endif
229 if (result == NULL)
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;
258 #else
259 return SJME_ERROR_NOT_IMPLEMENTED;
260 #endif
263 static sjme_errorCode sjme_nal_default_stdErrF(
264 sjme_attrInNotNull sjme_lpcstr format,
265 ...)
267 va_list list;
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. */
281 va_end(list);
283 /* Success? */
284 return error;
287 static sjme_errorCode sjme_nal_default_stdOutF(
288 sjme_attrInNotNull sjme_lpcstr format,
289 ...)
291 va_list list;
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. */
305 va_end(list);
307 /* Success? */
308 return error;
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)
323 switch (errNum)
325 case EIO:
326 return SJME_ERROR_IO_EXCEPTION;
328 case ENOENT:
329 return SJME_ERROR_FILE_NOT_FOUND;
332 return SJME_ERROR_UNKNOWN;