| 218 | } |
| 219 | |
| 220 | static void autovivify_ptr(lua_State *state, int fname_idx, void **pptr, |
| 221 | const type_identity *target, int val_index) |
| 222 | { |
| 223 | lua_getfield(state, val_index, "new"); |
| 224 | |
| 225 | // false or nil => bail out |
| 226 | if (!lua_toboolean(state, -1)) |
| 227 | field_error(state, fname_idx, "null and autovivify not requested", "write"); |
| 228 | |
| 229 | // not 'true' => call df.new() |
| 230 | if (!lua_isboolean(state, -1)) |
| 231 | { |
| 232 | int top = lua_gettop(state); |
| 233 | |
| 234 | // Verify new points to a reasonable type of object |
| 235 | const type_identity *suggested = get_object_identity(state, top, "autovivify", true, true); |
| 236 | |
| 237 | if (!is_type_compatible(state, target, 0, suggested, top+1, false)) |
| 238 | field_error(state, fname_idx, "incompatible suggested autovivify type", "write"); |
| 239 | |
| 240 | lua_pop(state, 1); |
| 241 | |
| 242 | // Invoke df.new() |
| 243 | lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); |
| 244 | lua_swap(state); |
| 245 | lua_call(state, 1, 1); |
| 246 | |
| 247 | // Retrieve the pointer |
| 248 | void *nval = get_object_internal(state, target, top, false); |
| 249 | |
| 250 | // shouldn't happen: this means suggested type is compatible, |
| 251 | // but its new() result isn't for some reason. |
| 252 | if (!nval) |
| 253 | field_error(state, fname_idx, "inconsistent autovivify type", "write"); |
| 254 | |
| 255 | *pptr = nval; |
| 256 | } |
| 257 | // otherwise use the target type |
| 258 | else |
| 259 | { |
| 260 | if (!target) |
| 261 | field_error(state, fname_idx, "trying to autovivify void*", "write"); |
| 262 | |
| 263 | *pptr = target->allocate(); |
| 264 | |
| 265 | if (!*pptr) |
| 266 | field_error(state, fname_idx, "could not allocate in autovivify", "write"); |
| 267 | } |
| 268 | |
| 269 | lua_pop(state, 1); |
| 270 | } |
| 271 | |
| 272 | static bool is_null(lua_State *state, int val_index) |
| 273 | { |
no test coverage detected