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.

286 lines
6.5 KiB

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