1 /* Jim - ANSI I/O extension
2 * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
4 * $Id: jim-aio.c,v 1.1.1.1 2008/07/31 20:44:21 mmahesh Exp $
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * A copy of the license is also included in the source distribution
13 * of Jim, as a TXT file name called LICENSE.
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
26 #include <pkgconf/athttpd.h>
30 #include <cyg/athttpd/jim.h>
32 #define AIO_CMD_LEN 128
33 #define AIO_BUF_LEN 1024
35 typedef struct AioFile {
37 int keepOpen; /* If set, the file is not fclosed on cleanup (stdin, ...) */
40 static void JimAioSetError(Jim_Interp *interp)
42 Jim_SetResultString(interp, strerror(errno), -1);
45 static void JimAioDelProc(Jim_Interp *interp, void *privData)
47 AioFile *af = privData;
55 /* Calls to [aio.file] create commands that are implemented by this
57 static int JimAioHandlerCommand(Jim_Interp *interp, int argc,
60 AioFile *af = Jim_CmdPrivData(interp);
62 const char *options[] = {
63 "close", "seek", "tell", "gets", "read", "puts", "flush", "eof", NULL
65 enum {OPT_CLOSE, OPT_SEEK, OPT_TELL, OPT_GETS, OPT_READ, OPT_PUTS,
69 Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
72 if (Jim_GetEnum(interp, argv[1], options, &option, "AIO method",
73 JIM_ERRMSG) != JIM_OK)
76 if (option == OPT_CLOSE) {
78 Jim_WrongNumArgs(interp, 2, argv, "");
81 Jim_DeleteCommand(interp, Jim_GetString(argv[0], NULL));
83 } else if (option == OPT_SEEK) {
88 if (argc != 3 && argc != 4) {
89 Jim_WrongNumArgs(interp, 2, argv, "offset ?origin?");
93 if (Jim_CompareStringImmediate(interp, argv[3], "start"))
95 else if (Jim_CompareStringImmediate(interp, argv[3], "current"))
97 else if (Jim_CompareStringImmediate(interp, argv[3], "end"))
100 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
101 Jim_AppendStrings(interp, Jim_GetResult(interp),
102 "bad origin \"", Jim_GetString(argv[3], NULL),
103 "\" must be: start, current, or end", NULL);
107 if (Jim_GetLong(interp, argv[2], &offset) != JIM_OK)
109 if (fseek(af->fp, offset, orig) == -1) {
110 JimAioSetError(interp);
114 } else if (option == OPT_TELL) {
119 Jim_WrongNumArgs(interp, 2, argv, "");
122 position = ftell(af->fp);
123 Jim_SetResult(interp, Jim_NewIntObj(interp, position));
125 } else if (option == OPT_GETS) {
127 char buf[AIO_BUF_LEN];
130 if (argc != 2 && argc != 3) {
131 Jim_WrongNumArgs(interp, 2, argv, "?varName?");
134 objPtr = Jim_NewStringObj(interp, NULL, 0);
137 buf[AIO_BUF_LEN-1] = '_';
138 if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
140 if (buf[AIO_BUF_LEN-1] == '\0' && buf[AIO_BUF_LEN-2] == '\n')
143 Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN-1);
146 Jim_AppendString(interp, objPtr, buf, strlen(buf)-1);
151 if (ferror(af->fp)) {
153 Jim_IncrRefCount(objPtr);
154 Jim_DecrRefCount(interp, objPtr);
155 JimAioSetError(interp);
158 /* On EOF returns -1 if varName was specified, or the empty string. */
159 if (feof(af->fp) && Jim_Length(objPtr) == 0) {
160 Jim_IncrRefCount(objPtr);
161 Jim_DecrRefCount(interp, objPtr);
163 Jim_SetResult(interp, Jim_NewIntObj(interp, -1));
169 Jim_GetString(objPtr, &totLen);
170 if (Jim_SetVariable(interp, argv[2], objPtr) != JIM_OK) {
171 Jim_IncrRefCount(objPtr);
172 Jim_DecrRefCount(interp, objPtr);
175 Jim_SetResult(interp, Jim_NewIntObj(interp, totLen));
177 Jim_SetResult(interp, objPtr);
180 } else if (option == OPT_READ) {
182 char buf[AIO_BUF_LEN];
185 int neededLen = -1; /* -1 is "read as much as possible" */
187 if (argc != 2 && argc != 3) {
188 Jim_WrongNumArgs(interp, 2, argv, "?-nonewline? ?len?");
192 Jim_CompareStringImmediate(interp, argv[2], "-nonewline"))
200 if (Jim_GetWide(interp, argv[2], &wideValue) != JIM_OK)
203 Jim_SetResultString(interp, "invalid parameter: negative len",
207 neededLen = (int) wideValue;
209 objPtr = Jim_NewStringObj(interp, NULL, 0);
210 while (neededLen != 0) {
214 if (neededLen == -1) {
215 readlen = AIO_BUF_LEN;
217 readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
219 retval = fread(buf, 1, readlen, af->fp);
221 Jim_AppendString(interp, objPtr, buf, retval);
222 if (neededLen != -1) {
226 if (retval != readlen) break;
228 /* Check for error conditions */
229 if (ferror(af->fp)) {
231 Jim_FreeNewObj(interp, objPtr);
232 JimAioSetError(interp);
237 const char *s = Jim_GetString(objPtr, &len);
239 if (len > 0 && s[len-1] == '\n') {
241 objPtr->bytes[objPtr->length] = '\0';
244 Jim_SetResult(interp, objPtr);
246 } else if (option == OPT_PUTS) {
251 if (argc != 3 && (argc != 4 || !Jim_CompareStringImmediate(
252 interp, argv[2], "-nonewline"))) {
253 Jim_WrongNumArgs(interp, 2, argv, "?-nonewline? string");
256 wdata = Jim_GetString(argv[2+(argc==4)], &wlen);
257 if (fwrite(wdata, 1, wlen, af->fp) != (unsigned)wlen ||
258 (argc == 3 && fwrite("\n", 1, 1, af->fp) != 1)) {
259 JimAioSetError(interp);
263 } else if (option == OPT_FLUSH) {
266 Jim_WrongNumArgs(interp, 2, argv, "");
269 if (fflush(af->fp) == EOF) {
270 JimAioSetError(interp);
274 } else if (option == OPT_EOF) {
277 Jim_WrongNumArgs(interp, 2, argv, "");
280 Jim_SetResult(interp, Jim_NewIntObj(interp, feof(af->fp)));
286 static int JimAioOpenCommand(Jim_Interp *interp, int argc,
287 Jim_Obj *const *argv)
291 char buf[AIO_CMD_LEN];
292 const char *mode = "r";
295 const char *options[] = {"input", "output", "error"};
296 enum {OPT_INPUT, OPT_OUTPUT, OPT_ERROR};
297 int keepOpen = 0, modeLen;
299 if (argc != 2 && argc != 3) {
300 Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
304 mode = Jim_GetString(argv[2], &modeLen);
305 if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "standard") &&
308 if (Jim_GetEnum(interp, argv[2], options, &option, "standard channel",
309 JIM_ERRMSG) != JIM_OK)
313 case OPT_INPUT: fp = stdin; break;
314 case OPT_OUTPUT: fp = stdout; break;
315 case OPT_ERROR: fp = stderr; break;
316 default: fp = NULL; Jim_Panic(interp,"default reached in JimAioOpenCommand()");
320 fp = fopen(Jim_GetString(argv[1], NULL), mode);
322 JimAioSetError(interp);
326 /* Get the next file id */
327 if (Jim_EvalGlobal(interp,
328 "if {[catch {incr aio.fileId}]} {set aio.fileId 0}") != JIM_OK)
330 objPtr = Jim_GetGlobalVariableStr(interp, "aio.fileId", JIM_ERRMSG);
331 if (objPtr == NULL) return JIM_ERR;
332 if (Jim_GetLong(interp, objPtr, &fileId) != JIM_OK) return JIM_ERR;
334 /* Create the file command */
335 af = Jim_Alloc(sizeof(*af));
337 af->keepOpen = keepOpen;
338 sprintf(buf, "aio.handle%ld", fileId);
339 Jim_CreateCommand(interp, buf, JimAioHandlerCommand, af, JimAioDelProc);
340 Jim_SetResultString(interp, buf, -1);
344 #ifndef JIM_STATICEXT
345 int Jim_OnLoad(Jim_Interp *interp)
347 int Jim_AioInit(Jim_Interp *interp)
350 #ifndef JIM_STATICEXT
351 Jim_InitExtension(interp);
353 if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG) != JIM_OK)
355 Jim_CreateCommand(interp, "aio.open", JimAioOpenCommand, NULL, NULL);