Object os_listdir() { Object list = list_new(10); Object path = arg_take_str_obj("listdir"); #ifdef _WIN32 WIN32_FIND_DATA Find_file_data; Object _path = obj_add(path, string_new("\\*.*")); HANDLE h_find = FindFirstFile(GET_STR(_path), &Find_file_data); if (h_find == INVALID_HANDLE_VALUE) { tm_raise("%s is not a directory", path); } do { if (strcmp(Find_file_data.cFileName, "..")==0 || strcmp(Find_file_data.cFileName, ".") == 0) { continue; } if (Find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // do nothing. } Object file = string_new(Find_file_data.cFileName); obj_append(list, file); } while (FindNextFile(h_find, &Find_file_data)); FindClose(h_find); #else tm_raise("listdir not implemented in posix."); #endif return list; }
Da_emulate_result Da_emulate(Da* d, CONTEXT * ctx, MemoryCache *mem, bool emulate_FS_accesses, address FS) { #ifdef _WIN64 return DA_NOT_EMULATED; #endif //bool SF=IS_SET(ctx->EFlags, FLAG_SF); //bool OF=IS_SET(ctx->EFlags, FLAG_OF); //bool ZF=IS_SET(ctx->EFlags, FLAG_ZF); bool CF=IS_SET(ctx->EFlags, FLAG_CF); bool b; if (x86_emu_debug) { // FIXME: write to log also? L ("%s() begin: [", __func__); Da_DumpString(&cur_fds, d); L ("]\n"); }; if ((emulate_FS_accesses==false && IS_SET(d->prefix_codes, PREFIX_FS)) || (IS_SET(d->prefix_codes, PREFIX_SS) || IS_SET(d->prefix_codes, PREFIX_GS))) { if (x86_emu_debug) L ("%s() skipping (data selector prefix present) at 0x" PRI_ADR_HEX "\n", __func__, CONTEXT_get_PC(ctx)); return DA_EMULATED_CANNOT_READ_MEMORY; }; switch (d->ins_code) { case I_CDQ: { uint32_t a=CONTEXT_get_Accum (ctx)&0xFFFFFFFF; CONTEXT_set_xDX (ctx, (a&0x80000000) ? 0xFFFFFFFF : 0); goto add_to_PC_and_return_OK; }; break; case I_PUSH: { address rt_adr; obj v; b=Da_op_get_value_of_op (&d->op[0], &rt_adr, ctx, mem, __FILE__, __LINE__, &v, d->prefix_codes, FS); if (b==false) { if (x86_emu_debug) L ("%s() I_PUSH: can't read memory\n", __func__); return DA_EMULATED_CANNOT_READ_MEMORY; }; b=DO_PUSH (ctx, mem, obj_get_as_REG(&v)); if (b==false) { if (x86_emu_debug) L ("%s() I_PUSH: can't write memory\n", __func__); return DA_EMULATED_CANNOT_WRITE_MEMORY; }; goto add_to_PC_and_return_OK; }; break; case I_PUSHFD: if (DO_PUSH (ctx, mem, ctx->EFlags | FLAG_TF)==false) { if (x86_emu_debug) L ("%s() I_PUSHFD: can't write memory\n", __func__); return DA_EMULATED_CANNOT_WRITE_MEMORY; }; goto add_to_PC_and_return_OK; break; case I_POP: { REG val; if (DO_POP(ctx, mem, &val)==false) return DA_EMULATED_CANNOT_READ_MEMORY; obj v; obj_tetrabyte2 (val, &v); Da_op_set_value_of_op (&d->op[0], &v, ctx, mem, d->prefix_codes, FS); goto add_to_PC_and_return_OK; }; break; case I_POPFD: { REG val; if (DO_POP(ctx, mem, &val)==false) return DA_EMULATED_CANNOT_READ_MEMORY; ctx->EFlags=val; goto add_to_PC_and_return_OK; }; break; case I_LEAVE: { //ESP <- EBP //POP EBP REG val; CONTEXT_set_SP(ctx, CONTEXT_get_BP(ctx)); if (DO_POP(ctx, mem, &val)==false) return DA_EMULATED_CANNOT_READ_MEMORY; // FIXME: а надо еще SP назад возвращать! CONTEXT_set_BP(ctx, val); goto add_to_PC_and_return_OK; }; break; case I_REP_STOSB: case I_REP_STOSW: case I_REP_STOSD: { BYTE *buf; bool DF=IS_SET(ctx->EFlags, FLAG_DF); if (DF) return DA_NOT_EMULATED; // not supported... bug here SIZE_T BUF_SIZE; if (d->ins_code==I_REP_STOSB) BUF_SIZE=CONTEXT_get_xCX (ctx); else if (d->ins_code==I_REP_STOSW) BUF_SIZE=CONTEXT_get_xCX (ctx)*2; else if (d->ins_code==I_REP_STOSD) BUF_SIZE=CONTEXT_get_xCX (ctx)*4; buf=DMALLOC(BYTE, BUF_SIZE, "buf"); if (d->ins_code==I_REP_STOSB) { for (REG i=0; i<CONTEXT_get_xCX(ctx); i++) // FIXME: rewrite to my own bzero()! buf[i]=CONTEXT_get_Accum(ctx)&0xFF; } else if (d->ins_code==I_REP_STOSW) { for (REG i=0; i<CONTEXT_get_xCX(ctx); i++) // FIXME: rewrite to my own bzero()! ((WORD*)buf)[i]=CONTEXT_get_Accum(ctx)&0xFFFF; } else if (d->ins_code==I_REP_STOSD) { for (REG i=0; i<CONTEXT_get_xCX(ctx); i++) // FIXME: rewrite to my own bzero()! ((DWORD*)buf)[i]=(DWORD)(CONTEXT_get_Accum(ctx)&0xFFFFFFFF); } else { oassert(0); }; if (MC_WriteBuffer (mem, CONTEXT_get_xDI (ctx), BUF_SIZE, buf)==false) return DA_EMULATED_CANNOT_WRITE_MEMORY; DFREE(buf); CONTEXT_set_xDI (ctx, CONTEXT_get_xDI (ctx) + BUF_SIZE); CONTEXT_set_xCX (ctx, 0); goto add_to_PC_and_return_OK; }; break; case I_REP_MOVSB: case I_REP_MOVSW: case I_REP_MOVSD: { BYTE *buf; bool DF=IS_SET(ctx->EFlags, FLAG_DF); if (DF) return DA_NOT_EMULATED; // not supported... bug here SIZE_T BUF_SIZE; SIZE_T sizeof_element; if (d->ins_code==I_REP_MOVSB) sizeof_element=1; else if (d->ins_code==I_REP_MOVSW) sizeof_element=2; else if (d->ins_code==I_REP_MOVSD) sizeof_element=4; else { oassert(0); }; BUF_SIZE=CONTEXT_get_xCX(ctx)*sizeof_element; //printf ("%s() BUF_SIZE=0x%x\n", __func__, BUF_SIZE); //printf ("%s() (before) SI=0x" PRI_REG_HEX "\n", __func__, CONTEXT_get_xSI(ctx)); //printf ("%s() (before) DI=0x" PRI_REG_HEX "\n", __func__, CONTEXT_get_xDI(ctx)); buf=DMALLOC(BYTE, BUF_SIZE, "buf"); address blk_src=CONTEXT_get_xSI(ctx); address blk_dst=CONTEXT_get_xDI(ctx); if (DF) { blk_src-=BUF_SIZE; // +sizeof_element; blk_dst-=BUF_SIZE; // +sizeof_element; }; if (MC_ReadBuffer (mem, blk_src, BUF_SIZE, buf)==false) { DFREE(buf); return DA_EMULATED_CANNOT_READ_MEMORY; }; if (MC_WriteBuffer (mem, blk_dst, BUF_SIZE, buf)==false) { DFREE(buf); return DA_EMULATED_CANNOT_WRITE_MEMORY; }; DFREE(buf); if (DF==false) { CONTEXT_set_xSI (ctx, CONTEXT_get_xSI (ctx) + BUF_SIZE); CONTEXT_set_xDI (ctx, CONTEXT_get_xDI (ctx) + BUF_SIZE); } else { CONTEXT_set_xSI (ctx, CONTEXT_get_xSI (ctx) - BUF_SIZE); CONTEXT_set_xDI (ctx, CONTEXT_get_xDI (ctx) - BUF_SIZE); }; CONTEXT_set_xCX (ctx, 0); //printf ("%s() (after) SI=0x" PRI_REG_HEX "\n", __func__, CONTEXT_get_xSI(ctx)); //printf ("%s() (after) DI=0x" PRI_REG_HEX "\n", __func__, CONTEXT_get_xDI(ctx)); goto add_to_PC_and_return_OK; }; case I_STD: SET_BIT (ctx->EFlags, FLAG_DF); goto add_to_PC_and_return_OK; case I_CLD: REMOVE_BIT (ctx->EFlags, FLAG_DF); goto add_to_PC_and_return_OK; case I_RETN: { WORD ret_arg=0; if (d->ops_total==1) { oassert (d->op[0].type==DA_OP_TYPE_VALUE); ret_arg=obj_get_as_wyde(&d->op[0].val._v); // RETN arg is 16-bit }; address newPC; if (DO_POP(ctx, mem, &newPC)==false) return DA_EMULATED_CANNOT_READ_MEMORY; CONTEXT_set_SP(ctx, CONTEXT_get_SP(ctx)+ret_arg); CONTEXT_set_PC(ctx, newPC); return DA_EMULATED_OK; }; break; case I_ADD: case I_ADC: case I_INC: { //L (__FUNCTION__ "() I_ADD/I_INC begin: [%s]\n", ToString().c_str()); obj rt1, rt2; REG rt1_adr, rt2_adr; b=Da_op_get_value_of_op (&d->op[0], &rt1_adr, ctx, mem, __FILE__, __LINE__, &rt1, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; if (d->ins_code==I_ADD || d->ins_code==I_ADC) { oassert (d->op[0].value_width_in_bits==d->op[1].value_width_in_bits); b=Da_op_get_value_of_op (&d->op[1], &rt2_adr, ctx, mem, __FILE__, __LINE__, &rt2, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; } else { // INC case // make second op 1 obj_REG2_and_set_type (rt1.t, 1, 0, &rt2); }; obj res_sum; obj_add (&rt1, &rt2, &res_sum); if (d->ins_code==I_ADC && CF) obj_increment(&res_sum); set_PF (ctx, &res_sum); set_SF (ctx, &res_sum); set_ZF (ctx, &res_sum); set_AF (ctx, &rt1, &rt2, &res_sum); if (d->ins_code==I_ADD || d->ins_code==I_ADC) set_or_clear_flag (ctx, FLAG_CF, obj_compare (&res_sum, &rt1)==-1); // res_sum < rt1 octabyte tmp=((zero_extend_to_REG(&rt1) ^ zero_extend_to_REG(&rt2) ^ get_sign_bit (d->op[0].value_width_in_bits)) & (zero_extend_to_REG(&res_sum) ^ zero_extend_to_REG(&rt1))) & get_sign_bit (d->op[0].value_width_in_bits); set_or_clear_flag (ctx, FLAG_OF, tmp); b=Da_op_set_value_of_op (&d->op[0], &res_sum, ctx, mem, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_WRITE_MEMORY; goto add_to_PC_and_return_OK; }; break; case I_NOT: { obj rt1, res; REG rt1_adr; if (Da_op_get_value_of_op (&d->op[0], &rt1_adr, ctx, mem, __FILE__, __LINE__, &rt1, d->prefix_codes, FS)==false) return DA_EMULATED_CANNOT_READ_MEMORY; obj_NOT(&rt1, &res); if (Da_op_set_value_of_op (&d->op[0], &res, ctx, mem, d->prefix_codes, FS)) goto add_to_PC_and_return_OK; }; break; case I_NEG: { obj rt1, res; REG rt1_adr; if (Da_op_get_value_of_op (&d->op[0], &rt1_adr, ctx, mem, __FILE__, __LINE__, &rt1, d->prefix_codes, FS)==false) return DA_EMULATED_CANNOT_READ_MEMORY; obj_NEG(&rt1, &res); set_or_clear_flag (ctx, FLAG_CF, obj_is_zero(&rt1)==false); set_PF (ctx, &res); set_SF (ctx, &res); set_ZF (ctx, &res); set_or_clear_flag (ctx, FLAG_AF, (0 ^ obj_get_4th_bit(&rt1)) ^ obj_get_4th_bit(&res)); REMOVE_BIT (ctx->EFlags, FLAG_OF); //SET_BIT (ctx->EFlags, FLAG_AF); if (Da_op_set_value_of_op (&d->op[0], &res, ctx, mem, d->prefix_codes, FS)) goto add_to_PC_and_return_OK; }; break; case I_OR: case I_XOR: case I_AND: case I_TEST: { oassert (d->op[0].value_width_in_bits==d->op[1].value_width_in_bits); obj rt1, rt2, res; REG rt1_adr, rt2_adr; b=Da_op_get_value_of_op (&d->op[0], &rt1_adr, ctx, mem, __FILE__, __LINE__, &rt1, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; b=Da_op_get_value_of_op (&d->op[1], &rt2_adr, ctx, mem, __FILE__, __LINE__, &rt2, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; switch (d->ins_code) { case I_OR: obj_OR(&rt1, &rt2, &res); break; case I_XOR: obj_XOR(&rt1, &rt2, &res); break; case I_TEST: case I_AND: obj_AND(&rt1, &rt2, &res); break; default: oassert(0); break; }; set_PF (ctx, &res); set_SF (ctx, &res); set_ZF (ctx, &res); REMOVE_BIT (ctx->EFlags, FLAG_AF); REMOVE_BIT (ctx->EFlags, FLAG_CF); REMOVE_BIT (ctx->EFlags, FLAG_OF); if (d->ins_code==I_TEST) b=true; else b=Da_op_set_value_of_op (&d->op[0], &res, ctx, mem, d->prefix_codes, FS); if (b) goto add_to_PC_and_return_OK; else return DA_EMULATED_CANNOT_WRITE_MEMORY; }; break; case I_DEC: case I_SUB: case I_SBB: case I_CMP: { if (d->ins_code==I_SUB || d->ins_code==I_SBB || d->ins_code==I_CMP) { oassert (d->op[0].value_width_in_bits==d->op[1].value_width_in_bits); }; obj rt1, rt2; REG rt1_adr, rt2_adr; b=Da_op_get_value_of_op (&d->op[0], &rt1_adr, ctx, mem, __FILE__, __LINE__, &rt1, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; if (d->ins_code==I_DEC) { // make second op 1 obj_REG2_and_set_type (rt1.t, 1, 0, &rt2); } else { b=Da_op_get_value_of_op (&d->op[1], &rt2_adr, ctx, mem, __FILE__, __LINE__, &rt2, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; }; obj res; obj_subtract (&rt1, &rt2, &res); if (d->ins_code==I_SBB && CF) obj_decrement (&res); set_PF (ctx, &res); set_SF (ctx, &res); set_ZF (ctx, &res); set_AF (ctx, &rt1, &rt2, &res); if (d->ins_code==I_SBB) { int tmp=(obj_compare (&rt1, &res)==-1 /* rt1<res */) || (CF && obj_get_as_tetrabyte(&rt2)==0xffffffff); set_or_clear_flag (ctx, FLAG_CF, tmp); } else { if (d->ins_code!=I_DEC) // DEC leave CF flag unaffected set_or_clear_flag (ctx, FLAG_CF, obj_compare (&rt1, &rt2)==-1); /* rt1<rt2 */ }; octabyte tmp=((zero_extend_to_octabyte(&rt1) ^ zero_extend_to_octabyte(&rt2)) & (zero_extend_to_octabyte(&res) ^ zero_extend_to_octabyte(&rt1))) & get_sign_bit (d->op[0].value_width_in_bits); set_or_clear_flag (ctx, FLAG_OF, tmp); if (d->ins_code==I_CMP) b=true; else b=Da_op_set_value_of_op (&d->op[0], &res, ctx, mem, d->prefix_codes, FS); if (b) goto add_to_PC_and_return_OK; else return DA_EMULATED_CANNOT_WRITE_MEMORY; }; break; case I_XCHG: { REG op1_adr, op2_adr; obj op1; b=Da_op_get_value_of_op(&d->op[0], &op1_adr, ctx, mem, __FILE__, __LINE__, &op1, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; obj op2; b=Da_op_get_value_of_op(&d->op[1], &op2_adr, ctx, mem, __FILE__, __LINE__, &op2, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; if (Da_op_set_value_of_op (&d->op[0], &op2, ctx, mem, d->prefix_codes, FS)==false) return DA_EMULATED_CANNOT_WRITE_MEMORY; if (Da_op_set_value_of_op (&d->op[1], &op1, ctx, mem, d->prefix_codes, FS)==false) return DA_EMULATED_CANNOT_WRITE_MEMORY; goto add_to_PC_and_return_OK; }; break; case I_MOV: case I_MOVDQA: case I_MOVDQU: return Da_emulate_MOV_op1_op2(d, ctx, mem, d->prefix_codes, FS); case I_MOVZX: case I_MOVSX: { address rt_adr; obj op2; bool b=Da_op_get_value_of_op(&d->op[1], &rt_adr, ctx, mem, __FILE__, __LINE__, &op2, d->prefix_codes, FS); if (b==false) { /* if (L_verbose_level>=2) { printf (__FUNCTION__ "(): ["); Da_DumpString(d); printf ("]: can't read src (2nd) operand\n"); }; */ return DA_EMULATED_CANNOT_WRITE_MEMORY; }; obj to_be_stored_v; if (d->ins_code==I_MOVZX) { enum obj_type op1_type_will_be=bit_width_to_obj_type (d->op[0].value_width_in_bits); obj_zero_extend (&op2, op1_type_will_be, &to_be_stored_v); } else if (d->ins_code==I_MOVSX) { enum obj_type op1_type_will_be=bit_width_to_obj_type (d->op[0].value_width_in_bits); obj_sign_extend (&op2, op1_type_will_be, &to_be_stored_v); } else { oassert (0); }; b=Da_op_set_value_of_op (&d->op[0], &to_be_stored_v, ctx, mem, d->prefix_codes, FS); if (b==false) { /* if (L_verbose_level>=2) { printf(__FUNCTION__ "(): ["); Da_DumpString(d); printf ("]: can't write dst (1st) operand\n"); }; */ return DA_EMULATED_CANNOT_WRITE_MEMORY; }; goto add_to_PC_and_return_OK; }; case I_NOP: goto add_to_PC_and_return_OK; case I_LEA: { address a=(address)Da_op_calc_adr_of_op(&d->op[1], ctx, mem, d->prefix_codes, FS); obj val; obj_tetrabyte2(a, &val); b=Da_op_set_value_of_op (&d->op[0], &val, ctx, mem, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_WRITE_MEMORY; goto add_to_PC_and_return_OK; }; case I_SAR: case I_SHR: case I_SHL: { // http://cs.smith.edu/~thiebaut/ArtOfAssembly/CH06/CH06-3.html REG op1_adr, op2_adr; obj op1; bool b=Da_op_get_value_of_op(&d->op[0], &op1_adr, ctx, mem, __FILE__, __LINE__, &op1, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; // should be read anyway! obj op2; b=Da_op_get_value_of_op(&d->op[1], &op2_adr, ctx, mem, __FILE__, __LINE__, &op2, d->prefix_codes, FS); if (b==false) return DA_EMULATED_CANNOT_READ_MEMORY; #ifdef _WIN64 obj_AND_with (&op2, 0x3F); #else obj_AND_with (&op2, 0x1F); #endif if (obj_is_zero(&op2)==false) { unsigned new_CF; if (d->ins_code==I_SHR || d->ins_code==I_SAR) new_CF=(zero_extend_to_octabyte(&op1) >> (obj_get_as_byte (&op2) - 1)) & 1; else // SHL new_CF=(zero_extend_to_octabyte(&op1) >> (obj_width_in_bits(&op1) - obj_get_as_byte (&op2))) & 1; obj new_op1; if (d->ins_code==I_SHR) { REG new_v=zero_extend_to_REG(&op1) >> obj_get_as_byte (&op2); obj_REG2_and_set_type(op1.t, new_v, 0, &new_op1); } else if (d->ins_code==I_SAR)
void _op_obj_import(void) { t_context *C=ctx_get(); char *filename=C->event->standby_string; if(filename) { // init list OBJECTS=lst_new("lst"); // parse file t_file *file = file_new(filename); free(C->event->standby_string); //C->event->standby_function=NULL; C->event->callback=NULL; file_read(file); file_read_lines(file); //parse words t_link *link; t_link *l; t_word *word; for(link=file->lines->first;link;link=link->next) { t_line *line = link->data; line_read_words(line); } // parse tokens int object_start; int line_object; int is_face; //int tot_object; int tot_vert; int tot_face; int tot_tri; int tot_quad; int tot_indice; char *object_name; //tot_object=0; tot_face=0; tot_quad=0; tot_tri=0; object_start=0; for(link=file->lines->first;link;link=link->next) { // LINE t_line *line = link->data; // RESET is_face=0; for(l=line->words->first;l;l=l->next) { // WORD word=l->data; if(word_equal(word,"o")) { if(object_start) { obj_add(object_name,tot_vert,tot_face,tot_quad,tot_tri); tot_vert=0; tot_face=0; tot_quad=0; tot_tri=0; free(object_name); } else { object_start=1; } tot_vert=0; line_object=1; } else if(line_object) { object_name=(char *)malloc(sizeof(char)*(strlen(word->data)+1)); strcpy(object_name,word->data); line_object=0; } else if(word_equal(word,"v")) { tot_vert++; } else if(word_equal(word,"f")) { tot_face++; is_face=1; tot_indice=0; } else if(is_face) { tot_indice++; } else if(word_equal(word,"usemtl")) { } else if(word_equal(word,"s")) { } } if(is_face) { if(tot_indice==4) { tot_quad++; } else { tot_tri++; } } } // add last object obj_add(object_name,tot_vert,tot_face,tot_quad,tot_tri); // vars int is_data=0; int indice_vertex=0; int indice_face=0; int cursor_tri=0; int cursor_quad=0; int global_cursor=0; int tmp_global_cursor=0; int face[4]; object_start=0; t_token_type token; t_link *link_object; t_obj *obj; for(link=file->lines->first;link;link=link->next) { // LINE t_line *line = link->data; // reset is_data=0; indice_face=0; for(l=line->words->first;l;l=l->next) { // WORD word=l->data; if(word_equal(word,"o")) { token=token_object; if(object_start) { if(link_object->next) link_object=link_object->next; obj=link_object->data; // global cursor global_cursor+=tmp_global_cursor; tmp_global_cursor=obj->tot_vert; } //first else { link_object=OBJECTS->first; obj=link_object->data; object_start=1; tmp_global_cursor=obj->tot_vert; } indice_vertex=0; indice_face=0; cursor_tri=0; cursor_quad=0; } else if(word_equal(word,"v")) { token=token_vertex; } else if(word_equal(word,"f")) { token=token_face; } else if(word_equal(word,"usemtl")) { token=token_material; } else if(word_equal(word,"s")) { token=token_unknown; } else { is_data=1; } if(is_data) { if(token==token_vertex) { obj->verts[indice_vertex]=atof(word->data); indice_vertex++; } else if(token==token_face) { face[indice_face]=atoi(word->data); indice_face++; } } } // store face indice if(token==token_face) { int i; if(indice_face==3) { for(i=0;i<3;i++) { obj->tris[cursor_tri]=face[i]-global_cursor-1; cursor_tri++; } } else { for(i=0;i<4;i++) { obj->quads[cursor_quad]=face[i]-global_cursor-1; cursor_quad++; } } } } // add objects to scene C->scene->store=1; for(link=OBJECTS->first;link;link=link->next) { t_obj *obj = link->data; // new mesh t_node *node_mesh=mesh_make( obj->name, //"me_obj", obj->tot_vert, obj->tot_face, obj->tot_quad, obj->tot_tri, obj->verts, obj->quads, obj->tris); // new object t_node *node_object=object_add("mesh",obj->name); // link t_object *object=node_object->data; object->cls->link(object,node_mesh); } C->scene->store=0; // free obj for(link=OBJECTS->first;link;link=link->next) { t_obj *obj = link->data; obj_free(obj); } } }