OpenSDE Framework (without history before r20070)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
6.5 KiB

  1. /*
  2. * --- SDE-COPYRIGHT-NOTE-BEGIN ---
  3. * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
  4. *
  5. * Filename: lib/lua/lzlib/lzlib.c
  6. * Copyright (C) 2008 The OpenSDE Project
  7. * Copyright (C) 2004 - 2006 The T2 SDE Project
  8. *
  9. * More information can be found in the files COPYING and README.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; version 2 of the License. A copy of the
  14. * GNU General Public License can be found in the file COPYING.
  15. * --- SDE-COPYRIGHT-NOTE-END ---
  16. */
  17. // compilation: gcc --shared lzlib.c -o lzlib.so -lz
  18. // contains some slightly addapted code pieces from lua's liolib.c
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <zlib.h>
  24. #include <lua.h>
  25. #include <lauxlib.h>
  26. #define ZLIB_HANDLE "gzFile"
  27. // ------------------- helper functions ------------------------
  28. // pushes gzFile operation result string on lua stack
  29. // first value is either true or nil (== operation failed),
  30. // in the latter case a string containing the error message and
  31. // the nummerical error codes (gzerror / errno) are returned
  32. // as additional values
  33. static int pushresult (lua_State *L, gzFile* zf, const char *filename)
  34. {
  35. int zlib_result;
  36. const char* zmessage;
  37. if ((zf) == NULL)
  38. zlib_result = Z_ERRNO;
  39. else
  40. zmessage = gzerror (*zf, &zlib_result);
  41. if (zlib_result == Z_OK) {
  42. lua_pushboolean(L, 1);
  43. return 1;
  44. } else {
  45. if (zlib_result == Z_ERRNO) // error is a file io error
  46. zmessage = strerror(errno);
  47. lua_pushnil(L);
  48. if (filename)
  49. lua_pushfstring(L, "%s: %s", filename, zmessage);
  50. else
  51. lua_pushfstring(L, "%s", zmessage);
  52. lua_pushinteger(L, zlib_result);
  53. lua_pushinteger(L, errno);
  54. return 4;
  55. }
  56. }
  57. // ensures first argument is an open zlib handle and returns it
  58. static gzFile *tozfile (lua_State *L)
  59. {
  60. gzFile *zf = ((gzFile *) luaL_checkudata(L, 1, ZLIB_HANDLE));
  61. if (*zf == NULL)
  62. luaL_error(L, "attempt to use a closed gz file");
  63. return zf;
  64. }
  65. // ----------------- poor man buffer in C ---------------------
  66. char* content_buffer = NULL;
  67. size_t content_buffer_length = 0;
  68. size_t content_length = 0;
  69. static inline void ResetBuffer ()
  70. {
  71. content_length = 0;
  72. }
  73. static inline void ExtendBufferBySize (size_t min_size)
  74. {
  75. if (min_size > content_buffer_length) {
  76. if (content_buffer_length == 0)
  77. content_buffer = malloc (min_size);
  78. else
  79. content_buffer = realloc (content_buffer, min_size);
  80. content_buffer_length = min_size;
  81. }
  82. }
  83. static inline void ExtendBuffer ()
  84. {
  85. ExtendBufferBySize ((content_buffer_length < 256) ? 256 : 2 * content_buffer_length);
  86. // for testing: ExtendBufferBySize ((content_buffer_length < 10) ? 10 : 2 + content_buffer_length);
  87. }
  88. static inline void AddToBuffer (char c)
  89. {
  90. if (content_buffer_length == content_length)
  91. ExtendBuffer ();
  92. content_buffer [content_length++] = c;
  93. }
  94. static inline const char* FinishBuffer ()
  95. {
  96. AddToBuffer ('\0');
  97. return content_buffer;
  98. }
  99. static inline int BufferFill ()
  100. {
  101. return content_length;
  102. }
  103. static inline int BufferFree ()
  104. {
  105. return (content_buffer_length - content_length);
  106. }
  107. // -------------------------- API ------------------------------
  108. static int gz_open (lua_State *L)
  109. {
  110. const char *filename = luaL_checkstring(L, 1);
  111. const char *mode = luaL_optstring(L, 2, "r");
  112. gzFile* zf = (gzFile *) lua_newuserdata(L, sizeof(gzFile));
  113. luaL_getmetatable(L, ZLIB_HANDLE);
  114. lua_setmetatable(L, -2);
  115. *zf = gzopen(filename, mode);
  116. return (*zf == NULL) ? pushresult(L, NULL, filename) : 1;
  117. }
  118. static int gz_close (lua_State *L)
  119. {
  120. gzFile *zf = tozfile(L);
  121. int result = gzclose(*zf);
  122. *zf = NULL;
  123. // need to emulate pushresult behavior, because gzerror
  124. // does not work anymore after closing stream *grrrr*
  125. if (result == Z_OK) {
  126. lua_pushboolean (L, 1);
  127. return 1;
  128. } else {
  129. const char* zmessage;
  130. if (result == Z_ERRNO) // error is a file io error
  131. zmessage = strerror(errno);
  132. else
  133. zmessage = zError(result);
  134. lua_pushnil(L);
  135. lua_pushfstring(L, zmessage);
  136. lua_pushinteger(L, result);
  137. lua_pushinteger(L, errno);
  138. return 4;
  139. }
  140. }
  141. static int __gz_lines_iterator (lua_State *L)
  142. {
  143. gzFile zf = (gzFile) lua_topointer (L, lua_upvalueindex(1));
  144. int ch = '\0';
  145. char* ret;
  146. if (content_buffer_length == 0)
  147. ExtendBuffer ();
  148. else
  149. ResetBuffer ();
  150. #ifdef READ_LINE_ONE_BY_ONE
  151. while ( (ch = gzgetc(zf)) != -1 && ch != '\n') {
  152. AddToBuffer ((char) ch);
  153. }
  154. #else
  155. do {
  156. ret = gzgets (zf, content_buffer + BufferFill (), BufferFree ());
  157. if (ret == Z_NULL)
  158. break;
  159. int l = strlen (content_buffer);
  160. content_length = l;
  161. if (l > 0) {
  162. ch = content_buffer[l - 1];
  163. if (ch != '\n')
  164. ExtendBuffer ();
  165. else
  166. content_buffer[l-1] = '\0';
  167. }
  168. } while (ret && ch != '\n');
  169. #endif
  170. if (ch == '\n' || BufferFill () > 0) {
  171. if (ch == '\n')
  172. lua_pushstring (L, FinishBuffer ());
  173. return 1;
  174. } else {
  175. return pushresult(L, &zf, NULL);
  176. }
  177. }
  178. static int gz_lines (lua_State *L)
  179. {
  180. gzFile *zf = tozfile(L);
  181. lua_pushlightuserdata (L, *zf);
  182. lua_pushcclosure (L, __gz_lines_iterator, 1);
  183. return 1;
  184. }
  185. static int gz_status (lua_State *L)
  186. {
  187. gzFile *zf = tozfile(L);
  188. return pushresult (L, zf, NULL);
  189. }
  190. static int gz_eof (lua_State *L)
  191. {
  192. gzFile *zf = tozfile(L);
  193. int eof = gzeof (*zf);
  194. lua_pushboolean(L, eof);
  195. if (eof == 1) {
  196. const char* eof_reason;
  197. int eof_reason_code;
  198. eof_reason = gzerror (*zf, &eof_reason_code);
  199. lua_pushboolean (L, eof_reason_code == Z_STREAM_END);
  200. lua_pushstring (L, eof_reason);
  201. return 3;
  202. }
  203. return 0;
  204. }
  205. // ------------------- init and registering --------------------
  206. static const luaL_reg R[] = {
  207. {"open", gz_open},
  208. {"close", gz_close},
  209. {"lines", gz_lines},
  210. {"status", gz_status},
  211. {"eof", gz_eof},
  212. {NULL, NULL}
  213. };
  214. static const luaL_Reg zlib[] = {
  215. {"close", gz_close},
  216. {"lines", gz_lines},
  217. {"status", gz_status},
  218. {"eof", gz_eof},
  219. {"__gc", gz_close},
  220. {NULL, NULL}
  221. };
  222. static void createmeta (lua_State *L) {
  223. luaL_newmetatable(L, ZLIB_HANDLE); /* create metatable for zlib handles */
  224. lua_pushvalue(L, -1); /* push metatable */
  225. lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
  226. luaL_register(L, NULL, zlib); /* gz file methods */
  227. }
  228. LUALIB_API int luaopen_lzlib (lua_State *L)
  229. {
  230. createmeta(L);
  231. luaL_openlib(L, "lzlib", R, 0);
  232. lua_pushliteral(L,"version"); /** version */
  233. lua_pushliteral(L,"pre-alpha");
  234. lua_settable(L,-3);
  235. return 1;
  236. }