diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1999-12-02 17:11:51 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1999-12-02 17:11:51 -0200 |
| commit | 72afb6debb981f0e7ae3bb0bc54cbf3c1ead88f2 (patch) | |
| tree | 90e31128def5232b115afc34c2f19c049e9b12a1 | |
| parent | b097076678a9ca637df9dae0089314acbb884dda (diff) | |
| download | lua-72afb6debb981f0e7ae3bb0bc54cbf3c1ead88f2.tar.gz lua-72afb6debb981f0e7ae3bb0bc54cbf3c1ead88f2.tar.bz2 lua-72afb6debb981f0e7ae3bb0bc54cbf3c1ead88f2.zip | |
modifications by lhf
| -rw-r--r-- | lundump.c | 182 | ||||
| -rw-r--r-- | lundump.h | 22 |
2 files changed, 104 insertions, 100 deletions
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lundump.c,v 1.14 1999/09/06 13:55:09 roberto Exp roberto $ | 2 | ** $Id: lundump.c,v 1.24 1999/12/02 18:45:03 lhf Exp $ |
| 3 | ** load bytecodes from files | 3 | ** load bytecodes from files |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #define LUA_REENTRANT | ||
| 8 | |||
| 9 | #include <stdio.h> | 7 | #include <stdio.h> |
| 10 | #include <string.h> | 8 | #include <string.h> |
| 9 | |||
| 10 | #define LUA_REENTRANT | ||
| 11 | |||
| 11 | #include "lauxlib.h" | 12 | #include "lauxlib.h" |
| 12 | #include "lfunc.h" | 13 | #include "lfunc.h" |
| 13 | #include "lmem.h" | 14 | #include "lmem.h" |
| @@ -15,195 +16,183 @@ | |||
| 15 | #include "lstring.h" | 16 | #include "lstring.h" |
| 16 | #include "lundump.h" | 17 | #include "lundump.h" |
| 17 | 18 | ||
| 18 | #define LoadBlock(L, b,size,Z) ezread(L, Z,b,size) | 19 | #define LoadBlock(L,b,size,Z) ezread(L,Z,b,size) |
| 19 | 20 | ||
| 20 | static void unexpectedEOZ (lua_State *L, ZIO* Z) | 21 | static void unexpectedEOZ (lua_State* L, ZIO* Z) |
| 21 | { | 22 | { |
| 22 | luaL_verror(L, "unexpected end of file in %s",zname(Z)); | 23 | luaL_verror(L,"unexpected end of file in %.255s",zname(Z)); |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | static int ezgetc (lua_State *L, ZIO* Z) | 26 | static int ezgetc (lua_State* L, ZIO* Z) |
| 26 | { | 27 | { |
| 27 | int c=zgetc(Z); | 28 | int c=zgetc(Z); |
| 28 | if (c==EOZ) unexpectedEOZ(L, Z); | 29 | if (c==EOZ) unexpectedEOZ(L,Z); |
| 29 | return c; | 30 | return c; |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | static void ezread (lua_State *L, ZIO* Z, void* b, int n) | 33 | static void ezread (lua_State* L, ZIO* Z, void* b, int n) |
| 33 | { | 34 | { |
| 34 | int r=zread(Z,b,n); | 35 | int r=zread(Z,b,n); |
| 35 | if (r!=0) unexpectedEOZ(L, Z); | 36 | if (r!=0) unexpectedEOZ(L,Z); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | static unsigned int LoadWord (lua_State *L, ZIO* Z) | 39 | static unsigned int LoadWord (lua_State* L, ZIO* Z) |
| 39 | { | 40 | { |
| 40 | unsigned int hi=ezgetc(L, Z); | 41 | unsigned int hi=ezgetc(L,Z); |
| 41 | unsigned int lo=ezgetc(L, Z); | 42 | unsigned int lo=ezgetc(L,Z); |
| 42 | return (hi<<8)|lo; | 43 | return (hi<<8)|lo; |
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | static unsigned long LoadLong (lua_State *L, ZIO* Z) | 46 | static unsigned long LoadLong (lua_State* L, ZIO* Z) |
| 46 | { | 47 | { |
| 47 | unsigned long hi=LoadWord(L, Z); | 48 | unsigned long hi=LoadWord(L,Z); |
| 48 | unsigned long lo=LoadWord(L, Z); | 49 | unsigned long lo=LoadWord(L,Z); |
| 49 | return (hi<<16)|lo; | 50 | return (hi<<16)|lo; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | /* | 53 | static real LoadNumber (lua_State* L, ZIO* Z, int native) |
| 53 | * convert number from text | ||
| 54 | */ | ||
| 55 | real luaU_str2d (lua_State *L, const char* b, const char* where) | ||
| 56 | { | 54 | { |
| 57 | real x; | ||
| 58 | if (!luaO_str2d(b, &x)) | ||
| 59 | luaL_verror(L, "cannot convert number '%s' in %s",b,where); | ||
| 60 | return x; | ||
| 61 | } | ||
| 62 | |||
| 63 | static real LoadNumber (lua_State *L, ZIO* Z, int native) | ||
| 64 | { | ||
| 65 | real x; | ||
| 66 | if (native) | 55 | if (native) |
| 67 | { | 56 | { |
| 68 | LoadBlock(L, &x,sizeof(x),Z); | 57 | real x; |
| 58 | LoadBlock(L,&x,sizeof(x),Z); | ||
| 69 | return x; | 59 | return x; |
| 70 | } | 60 | } |
| 71 | else | 61 | else |
| 72 | { | 62 | { |
| 73 | char b[256]; | 63 | char b[256]; |
| 74 | int size=ezgetc(L, Z); | 64 | int size=ezgetc(L,Z); |
| 75 | LoadBlock(L, b,size,Z); | 65 | LoadBlock(L,b,size,Z); |
| 76 | b[size]=0; | 66 | b[size]=0; |
| 77 | return luaU_str2d(L, b,zname(Z)); | 67 | return luaU_str2d(L,b,zname(Z)); |
| 78 | } | 68 | } |
| 79 | } | 69 | } |
| 80 | 70 | ||
| 81 | static int LoadInt (lua_State *L, ZIO* Z, const char* message) | 71 | static int LoadInt (lua_State* L, ZIO* Z, const char* message) |
| 82 | { | 72 | { |
| 83 | unsigned long l=LoadLong(L, Z); | 73 | unsigned long l=LoadLong(L,Z); |
| 84 | unsigned int i=l; | 74 | unsigned int i=l; |
| 85 | if (i!=l) luaL_verror(L, message,l,zname(Z)); | 75 | if (i!=l) luaL_verror(L,message,l,zname(Z)); |
| 86 | return i; | 76 | return i; |
| 87 | } | 77 | } |
| 88 | 78 | ||
| 89 | #define PAD 5 /* two word operands plus opcode */ | 79 | #define PAD 5 /* two word operands plus opcode */ |
| 90 | 80 | ||
| 91 | static Byte* LoadCode (lua_State *L, ZIO* Z) | 81 | static Byte* LoadCode (lua_State* L, ZIO* Z) |
| 92 | { | 82 | { |
| 93 | int size=LoadInt(L, Z,"code too long (%ld bytes) in %s"); | 83 | int size=LoadInt(L,Z,"code too long (%lu bytes) in %.255s"); |
| 94 | Byte* b=luaM_malloc(L, size+PAD); | 84 | Byte* b=luaM_malloc(L,size+PAD); |
| 95 | LoadBlock(L, b,size,Z); | 85 | LoadBlock(L,b,size,Z); |
| 96 | if (b[size-1]!=ENDCODE) luaL_verror(L, "bad code in %s",zname(Z)); | 86 | if (b[size-1]!=ENDCODE) luaL_verror(L,"bad code in %.255s",zname(Z)); |
| 97 | memset(b+size,ENDCODE,PAD); /* pad code for safety */ | 87 | memset(b+size,ENDCODE,PAD); /* pad code for safety */ |
| 98 | return b; | 88 | return b; |
| 99 | } | 89 | } |
| 100 | 90 | ||
| 101 | static TaggedString* LoadTString (lua_State *L, ZIO* Z) | 91 | static TaggedString* LoadTString (lua_State* L, ZIO* Z) |
| 102 | { | 92 | { |
| 103 | long size=LoadLong(L, Z); | 93 | long size=LoadLong(L,Z); |
| 104 | if (size==0) | 94 | if (size==0) |
| 105 | return NULL; | 95 | return NULL; |
| 106 | else | 96 | else |
| 107 | { | 97 | { |
| 108 | char* s=luaL_openspace(L, size); | 98 | char* s=luaL_openspace(L,size); |
| 109 | LoadBlock(L, s,size,Z); | 99 | LoadBlock(L,s,size,Z); |
| 110 | return luaS_newlstr(L, s,size-1); | 100 | return luaS_newlstr(L,s,size-1); |
| 111 | } | 101 | } |
| 112 | } | 102 | } |
| 113 | 103 | ||
| 114 | static void LoadLocals (lua_State *L, TProtoFunc* tf, ZIO* Z) | 104 | static void LoadLocals (lua_State* L, TProtoFunc* tf, ZIO* Z) |
| 115 | { | 105 | { |
| 116 | int i,n=LoadInt(L, Z,"too many locals (%ld) in %s"); | 106 | int i,n=LoadInt(L,Z,"too many locals (%lu) in %.255s"); |
| 117 | if (n==0) return; | 107 | if (n==0) return; |
| 118 | tf->locvars=luaM_newvector(L, n+1,LocVar); | 108 | tf->locvars=luaM_newvector(L,n+1,LocVar); |
| 119 | for (i=0; i<n; i++) | 109 | for (i=0; i<n; i++) |
| 120 | { | 110 | { |
| 121 | tf->locvars[i].line=LoadInt(L, Z,"too many lines (%ld) in %s"); | 111 | tf->locvars[i].line=LoadInt(L,Z,"too many lines (%lu) in %.255s"); |
| 122 | tf->locvars[i].varname=LoadTString(L, Z); | 112 | tf->locvars[i].varname=LoadTString(L,Z); |
| 123 | } | 113 | } |
| 124 | tf->locvars[i].line=-1; /* flag end of vector */ | 114 | tf->locvars[i].line=-1; /* flag end of vector */ |
| 125 | tf->locvars[i].varname=NULL; | 115 | tf->locvars[i].varname=NULL; |
| 126 | } | 116 | } |
| 127 | 117 | ||
| 128 | static TProtoFunc* LoadFunction (lua_State *L, ZIO* Z, int native); | 118 | static TProtoFunc* LoadFunction (lua_State* L, ZIO* Z, int native); |
| 129 | 119 | ||
| 130 | static void LoadConstants (lua_State *L, TProtoFunc* tf, ZIO* Z, int native) | 120 | static void LoadConstants (lua_State* L, TProtoFunc* tf, ZIO* Z, int native) |
| 131 | { | 121 | { |
| 132 | int i,n=LoadInt(L, Z,"too many constants (%ld) in %s"); | 122 | int i,n=LoadInt(L,Z,"too many constants (%lu) in %.255s"); |
| 133 | tf->nconsts=n; | 123 | tf->nconsts=n; |
| 134 | if (n==0) return; | 124 | if (n==0) return; |
| 135 | tf->consts=luaM_newvector(L, n,TObject); | 125 | tf->consts=luaM_newvector(L,n,TObject); |
| 136 | for (i=0; i<n; i++) | 126 | for (i=0; i<n; i++) |
| 137 | { | 127 | { |
| 138 | TObject* o=tf->consts+i; | 128 | TObject* o=tf->consts+i; |
| 139 | ttype(o)=-ezgetc(L, Z); /* ttype(o) is negative - ORDER LUA_T */ | 129 | ttype(o)=-ezgetc(L,Z); /* ttype(o) is negative - ORDER LUA_T */ |
| 140 | switch (ttype(o)) | 130 | switch (ttype(o)) |
| 141 | { | 131 | { |
| 142 | case LUA_T_NUMBER: | 132 | case LUA_T_NUMBER: |
| 143 | nvalue(o)=LoadNumber(L, Z,native); | 133 | nvalue(o)=LoadNumber(L,Z,native); |
| 144 | break; | 134 | break; |
| 145 | case LUA_T_STRING: | 135 | case LUA_T_STRING: |
| 146 | tsvalue(o)=LoadTString(L, Z); | 136 | tsvalue(o)=LoadTString(L,Z); |
| 147 | break; | 137 | break; |
| 148 | case LUA_T_PROTO: | 138 | case LUA_T_PROTO: |
| 149 | tfvalue(o)=LoadFunction(L, Z,native); | 139 | tfvalue(o)=LoadFunction(L,Z,native); |
| 150 | break; | 140 | break; |
| 151 | case LUA_T_NIL: | 141 | case LUA_T_NIL: |
| 152 | break; | 142 | break; |
| 153 | default: /* cannot happen */ | 143 | default: /* cannot happen */ |
| 154 | luaU_badconstant(L, "load",i,o,tf); | 144 | luaU_badconstant(L,"load",i,o,tf); |
| 155 | break; | 145 | break; |
| 156 | } | 146 | } |
| 157 | } | 147 | } |
| 158 | } | 148 | } |
| 159 | 149 | ||
| 160 | static TProtoFunc* LoadFunction (lua_State *L, ZIO* Z, int native) | 150 | static TProtoFunc* LoadFunction (lua_State* L, ZIO* Z, int native) |
| 161 | { | 151 | { |
| 162 | TProtoFunc* tf=luaF_newproto(L); | 152 | TProtoFunc* tf=luaF_newproto(L); |
| 163 | tf->lineDefined=LoadInt(L, Z,"lineDefined too large (%ld) in %s"); | 153 | tf->lineDefined=LoadInt(L,Z,"lineDefined too large (%lu) in %.255s"); |
| 164 | tf->source=LoadTString(L, Z); | 154 | tf->source=LoadTString(L,Z); |
| 165 | if (tf->source==NULL) tf->source=luaS_new(L, zname(Z)); | 155 | if (tf->source==NULL) tf->source=luaS_new(L,zname(Z)); |
| 166 | tf->code=LoadCode(L, Z); | 156 | tf->code=LoadCode(L,Z); |
| 167 | LoadLocals(L, tf,Z); | 157 | LoadLocals(L,tf,Z); |
| 168 | LoadConstants(L, tf,Z,native); | 158 | LoadConstants(L,tf,Z,native); |
| 169 | return tf; | 159 | return tf; |
| 170 | } | 160 | } |
| 171 | 161 | ||
| 172 | static void LoadSignature (lua_State *L, ZIO* Z) | 162 | static void LoadSignature (lua_State* L, ZIO* Z) |
| 173 | { | 163 | { |
| 174 | const char* s=SIGNATURE; | 164 | const char* s=SIGNATURE; |
| 175 | while (*s!=0 && ezgetc(L, Z)==*s) | 165 | while (*s!=0 && ezgetc(L,Z)==*s) |
| 176 | ++s; | 166 | ++s; |
| 177 | if (*s!=0) luaL_verror(L, "bad signature in %s",zname(Z)); | 167 | if (*s!=0) luaL_verror(L,"bad signature in %.255s",zname(Z)); |
| 178 | } | 168 | } |
| 179 | 169 | ||
| 180 | static int LoadHeader (lua_State *L, ZIO* Z) | 170 | static int LoadHeader (lua_State* L, ZIO* Z) |
| 181 | { | 171 | { |
| 182 | int version,sizeofR; | 172 | int version,sizeofR,native; |
| 183 | int native; | 173 | LoadSignature(L,Z); |
| 184 | LoadSignature(L, Z); | 174 | version=ezgetc(L,Z); |
| 185 | version=ezgetc(L, Z); | ||
| 186 | if (version>VERSION) | 175 | if (version>VERSION) |
| 187 | luaL_verror(L, | 176 | luaL_verror(L, |
| 188 | "%s too new: version=0x%02x; expected at most 0x%02x", | 177 | "%.255s too new: version=0x%02x; expected at most 0x%02x", |
| 189 | zname(Z),version,VERSION); | 178 | zname(Z),version,VERSION); |
| 190 | if (version<VERSION0) /* check last major change */ | 179 | if (version<VERSION0) /* check last major change */ |
| 191 | luaL_verror(L, | 180 | luaL_verror(L, |
| 192 | "%s too old: version=0x%02x; expected at least 0x%02x", | 181 | "%.255s too old: version=0x%02x; expected at least 0x%02x", |
| 193 | zname(Z),version,VERSION0); | 182 | zname(Z),version,VERSION0); |
| 194 | sizeofR=ezgetc(L, Z); | 183 | sizeofR=ezgetc(L,Z); |
| 195 | native=(sizeofR!=0); | 184 | native=(sizeofR!=0); |
| 196 | if (native) /* test number representation */ | 185 | if (native) /* test number representation */ |
| 197 | { | 186 | { |
| 198 | if (sizeofR!=sizeof(real)) | 187 | if (sizeofR!=sizeof(real)) |
| 199 | luaL_verror(L, "unknown number size in %s: read %d; expected %d", | 188 | luaL_verror(L,"unknown number size in %.255s: read %d; expected %d", |
| 200 | zname(Z),sizeofR,sizeof(real)); | 189 | zname(Z),sizeofR,(int)sizeof(real)); |
| 201 | else | 190 | else |
| 202 | { | 191 | { |
| 203 | real tf=TEST_NUMBER; | 192 | real tf=TEST_NUMBER; |
| 204 | real f=LoadNumber(L, Z,native); | 193 | real f=LoadNumber(L,Z,native); |
| 205 | if ((long)f!=(long)tf) | 194 | if ((long)f!=(long)tf) |
| 206 | luaL_verror(L, "unknown number format in %s: " | 195 | luaL_verror(L,"unknown number format in %.255s: " |
| 207 | "read " NUMBER_FMT "; expected " NUMBER_FMT, | 196 | "read " NUMBER_FMT "; expected " NUMBER_FMT, |
| 208 | zname(Z),f,tf); | 197 | zname(Z),f,tf); |
| 209 | } | 198 | } |
| @@ -211,31 +200,42 @@ static int LoadHeader (lua_State *L, ZIO* Z) | |||
| 211 | return native; | 200 | return native; |
| 212 | } | 201 | } |
| 213 | 202 | ||
| 214 | static TProtoFunc* LoadChunk (lua_State *L, ZIO* Z) | 203 | static TProtoFunc* LoadChunk (lua_State* L, ZIO* Z) |
| 215 | { | 204 | { |
| 216 | return LoadFunction(L, Z,LoadHeader(L, Z)); | 205 | return LoadFunction(L,Z,LoadHeader(L,Z)); |
| 217 | } | 206 | } |
| 218 | 207 | ||
| 219 | /* | 208 | /* |
| 220 | ** load one chunk from a file or buffer | 209 | ** load one chunk from a file or buffer |
| 221 | ** return main if ok and NULL at EOF | 210 | ** return main if ok and NULL at EOF |
| 222 | */ | 211 | */ |
| 223 | TProtoFunc* luaU_undump1 (lua_State *L, ZIO* Z) | 212 | TProtoFunc* luaU_undump1 (lua_State* L, ZIO* Z) |
| 224 | { | 213 | { |
| 225 | int c=zgetc(Z); | 214 | int c=zgetc(Z); |
| 226 | if (c==ID_CHUNK) | 215 | if (c==ID_CHUNK) |
| 227 | return LoadChunk(L, Z); | 216 | return LoadChunk(L,Z); |
| 228 | else if (c!=EOZ) | 217 | else if (c!=EOZ) |
| 229 | luaL_verror(L, "%s is not a Lua binary file",zname(Z)); | 218 | luaL_verror(L,"%.255s is not a Lua binary file",zname(Z)); |
| 230 | return NULL; | 219 | return NULL; |
| 231 | } | 220 | } |
| 232 | 221 | ||
| 233 | /* | 222 | /* |
| 234 | * handle constants that cannot happen | 223 | * handle constants that cannot happen |
| 235 | */ | 224 | */ |
| 236 | void luaU_badconstant (lua_State *L, const char* s, int i, const TObject* o, TProtoFunc* tf) | 225 | void luaU_badconstant (lua_State* L, const char* s, int i, const TObject* o, const TProtoFunc* tf) |
| 237 | { | 226 | { |
| 238 | int t=ttype(o); | 227 | int t=ttype(o); |
| 239 | const char* name= (t>0 || t<LUA_T_LINE) ? "?" : luaO_typenames[-t]; | 228 | const char* name= (t>0 || t<LUA_T_LINE) ? "?" : luaO_typenames[-t]; |
| 240 | luaL_verror(L, "cannot %s constant #%d: type=%d [%s]" IN,s,i,t,name,INLOC); | 229 | luaL_verror(L,"cannot %.255s constant #%d: type=%d [%s]" IN,s,i,t,name,INLOC); |
| 230 | } | ||
| 231 | |||
| 232 | /* | ||
| 233 | * convert number from text | ||
| 234 | */ | ||
| 235 | double luaU_str2d (lua_State* L, const char* b, const char* where) | ||
| 236 | { | ||
| 237 | double x; | ||
| 238 | if (!luaO_str2d(b,&x)) | ||
| 239 | luaL_verror(L,"cannot convert number '%.255s' in %.255s",b,where); | ||
| 240 | return x; | ||
| 241 | } | 241 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lundump.h,v 1.10 1999/08/16 20:52:00 roberto Exp roberto $ | 2 | ** $Id: lundump.h,v 1.17 1999/12/02 18:51:09 lhf Exp $ |
| 3 | ** load pre-compiled Lua chunks | 3 | ** load pre-compiled Lua chunks |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -10,20 +10,24 @@ | |||
| 10 | #include "lobject.h" | 10 | #include "lobject.h" |
| 11 | #include "lzio.h" | 11 | #include "lzio.h" |
| 12 | 12 | ||
| 13 | TProtoFunc* luaU_undump1 (lua_State *L, ZIO* Z); /* load one chunk */ | 13 | /* load one chunk */ |
| 14 | void luaU_badconstant (lua_State *L, const char* s, int i, const TObject* o, TProtoFunc* tf); | 14 | TProtoFunc* luaU_undump1 (lua_State* L, ZIO* Z); |
| 15 | /* handle cases that cannot happen */ | 15 | |
| 16 | double luaU_str2d (lua_State *L, const char* b, const char* where); | 16 | /* handle cases that cannot happen */ |
| 17 | /* convert number from text */ | 17 | void luaU_badconstant (lua_State* L, const char* s, int i, |
| 18 | const TObject* o, const TProtoFunc* tf); | ||
| 19 | |||
| 20 | /* convert number from text */ | ||
| 21 | double luaU_str2d (lua_State* L, const char* b, const char* where); | ||
| 18 | 22 | ||
| 19 | /* definitions for headers of binary files */ | 23 | /* definitions for headers of binary files */ |
| 20 | #define VERSION 0x32 /* last format change was in 3.2 */ | 24 | #define VERSION 0x33 /* last format change was in 3.3 */ |
| 21 | #define VERSION0 0x32 /* last major change was in 3.2 */ | 25 | #define VERSION0 0x33 /* last major change was in 3.3 */ |
| 22 | #define ID_CHUNK 27 /* binary files start with ESC... */ | 26 | #define ID_CHUNK 27 /* binary files start with ESC... */ |
| 23 | #define SIGNATURE "Lua" /* ...followed by this signature */ | 27 | #define SIGNATURE "Lua" /* ...followed by this signature */ |
| 24 | 28 | ||
| 25 | /* formats for error messages */ | 29 | /* formats for error messages */ |
| 26 | #define SOURCE "<%s:%d>" | 30 | #define SOURCE "<%.255s:%d>" |
| 27 | #define IN " in %p " SOURCE | 31 | #define IN " in %p " SOURCE |
| 28 | #define INLOC tf,tf->source->str,tf->lineDefined | 32 | #define INLOC tf,tf->source->str,tf->lineDefined |
| 29 | 33 | ||
