static void push_sprintf_state (void) { sprintf_state_t *state; state = ALLOCATE(sprintf_state_t, TAG_TEMPORARY, "push_sprintf_state"); outbuf_zero(&(state->obuff)); state->csts = NULL; state->cur_arg = -1; state->clean.type = T_NUMBER; state->clean.u.number = 0; state->next = sprintf_state; sprintf_state = state; }
void f_db_status (void) { int i; outbuffer_t out; outbuf_zero(&out); for (i = 0; i < dbConnAlloc; i++) { if (dbConnList[i].flags & DB_FLAG_EMPTY) { continue; } outbuf_addv(&out, "Handle: %d (%s)\n", i + 1, dbConnList[i].type->name); if (dbConnList[i].type->status != NULL) { dbConnList[i].type->status(&(dbConnList[i].c), &out); } } outbuf_push(&out); }
void f_debug_info (void) { svalue_t *arg; outbuffer_t out; outbuf_zero(&out); arg = sp - 1; switch (arg[0].u.number) { case 0: { int i, flags; object_t *obj2; ob = arg[1].u.ob; flags = ob->flags; outbuf_addv(&out, "O_HEART_BEAT : %s\n", flags & O_HEART_BEAT ? "TRUE" : "FALSE"); #ifndef NO_WIZARDS outbuf_addv(&out, "O_IS_WIZARD : %s\n", flags & O_IS_WIZARD ? "TRUE" : "FALSE"); #endif #ifdef NO_ADD_ACTION outbuf_addv(&out, "O_LISTENER : %s\n", flags & O_LISTENER ? "TRUE" : "FALSE"); #else outbuf_addv(&out, "O_ENABLE_COMMANDS : %s\n", flags & O_ENABLE_COMMANDS ? "TRUE" : "FALSE"); #endif outbuf_addv(&out, "O_CLONE : %s\n", flags & O_CLONE ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_VIRTUAL : %s\n", flags & O_VIRTUAL ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_DESTRUCTED : %s\n", flags & O_DESTRUCTED ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_ONCE_INTERACTIVE: %s\n", flags & O_ONCE_INTERACTIVE ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_RESET_STATE : %s\n", flags & O_RESET_STATE ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_WILL_CLEAN_UP : %s\n", flags & O_WILL_CLEAN_UP ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_WILL_RESET : %s\n", flags & O_WILL_RESET ? "TRUE" : "FALSE"); #ifdef HAVE_ZLIB if (ob->interactive) { outbuf_addv(&out, "O_COMPRESSED : %s\n", ob->interactive->compressed_stream ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_ZMP : %s\n", ob->interactive->iflags & USING_ZMP ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_GMCP : %s\n", ob->interactive->iflags & USING_GMCP ? "TRUE" : "FALSE"); outbuf_addv(&out, "O_MXP : %s\n", ob->interactive->iflags & USING_MXP ? "TRUE" : "FALSE"); } #endif #ifndef NO_LIGHT outbuf_addv(&out, "total light : %d\n", ob->total_light); #endif #ifndef NO_RESETS outbuf_addv(&out, "next_reset : %d\n", ob->next_reset); #endif outbuf_addv(&out, "time_of_ref : %d\n", ob->time_of_ref); outbuf_addv(&out, "ref : %d\n", ob->ref); #ifdef DEBUG outbuf_addv(&out, "extra_ref : %d\n", ob->extra_ref); #endif outbuf_addv(&out, "name : '/%s'\n", ob->obname); outbuf_addv(&out, "next_all : OBJ(/%s)\n", ob->next_all ? ob->next_all->obname : "NULL"); if (obj_list == ob) outbuf_add(&out, "This object is the head of the object list.\n"); for (obj2 = obj_list, i = 1; obj2; obj2 = obj2->next_all, i++) if (obj2->next_all == ob) { outbuf_addv(&out, "Previous object in object list: OBJ(/%s)\n", obj2->obname); outbuf_addv(&out, "position in object list:%d\n", i); } break; } case 1: ob = arg[1].u.ob; outbuf_addv(&out, "program ref's %d\n", ob->prog->ref); outbuf_addv(&out, "Name /%s\n", ob->prog->filename); outbuf_addv(&out, "program size %d\n", ob->prog->program_size); outbuf_addv(&out, "function flags table %d (%d) \n", ob->prog->last_inherited + ob->prog->num_functions_defined, (ob->prog->last_inherited + ob->prog->num_functions_defined)* sizeof(unsigned short)); outbuf_addv(&out, "compiler function table %d (%d) \n", ob->prog->num_functions_defined, ob->prog->num_functions_defined * sizeof(function_t)); outbuf_addv(&out, "num strings %d\n", ob->prog->num_strings); outbuf_addv(&out, "num vars %d (%d)\n", ob->prog->num_variables_defined, ob->prog->num_variables_defined * (sizeof(char *) + sizeof(short))); outbuf_addv(&out, "num inherits %d (%d)\n", ob->prog->num_inherited, ob->prog->num_inherited * sizeof(inherit_t)); outbuf_addv(&out, "total size %d\n", ob->prog->total_size); break; case 2: { int i; ob = arg[1].u.ob; for (i=0; i<ob->prog->num_variables_total; i++) { /* inefficient, but: */ outbuf_addv(&out, "%s: ", variable_name(ob->prog, i)); svalue_to_string(&ob->variables[i], &out, 2, 0, 0); outbuf_add(&out, "\n"); } break; } default: bad_arg(1, F_DEBUG_INFO); } pop_stack(); pop_stack(); outbuf_push(&out); }
/* * THE (s)printf() function. * It returns a pointer to it's internal buffer (or a string in the text * segment) thus, the string must be copied if it has to survive after * this function is called again, or if it's going to be modified (esp. * if it risks being free()ed). */ char *string_print_formatted (const char * format_str, int argc, svalue_t * argv) { format_info finfo; svalue_t *carg; /* current arg */ unsigned int nelemno = 0; /* next offset into array */ unsigned int fpos; /* position in format_str */ int fs; /* field size */ int pres; /* precision */ pad_info_t pad; /* fs pad string */ unsigned int i; char *retvalue; int last; push_sprintf_state(); STACK_INC; sp->type = T_ERROR_HANDLER; sp->u.error_handler = pop_sprintf_state; last = 0; for (fpos = 0; 1; fpos++) { char c = format_str[fpos]; if (c == '\n' || !c) { int column_stat = 0; if (last != fpos) { add_nstr(format_str + last, fpos - last); last = fpos + 1; } else last++; if (!sprintf_state->csts) { if (!c) break; ADD_CHAR('\n'); continue; } ADD_CHAR('\n'); while (sprintf_state->csts) { cst **temp; temp = &(sprintf_state->csts); while (*temp) { if ((*temp)->info & INFO_COLS) { if (*((*temp)->d.col - 1) != '\n') while (*((*temp)->d.col) == ' ') (*temp)->d.col++; add_pad(0, (*temp)->start - get_curpos()); column_stat = add_column(temp, 0); if (!column_stat) temp = &((*temp)->next); } else { add_pad(0, (*temp)->start - get_curpos()); if (!add_table(temp)) temp = &((*temp)->next); } } /* of while (*temp) */ if (sprintf_state->csts || c == '\n') ADD_CHAR('\n'); } /* of while (sprintf_state->csts) */ if (column_stat == 2) ADD_CHAR('\n'); if (!c) break; } else if (c == '%') { if (last != fpos) { add_nstr(format_str + last, fpos - last); last = fpos + 1; } else last++; if (format_str[fpos + 1] == '%') { ADD_CHAR('%'); fpos++; last++; continue; } GET_NEXT_ARG; fs = 0; pres = 0; pad.len = 0; finfo = 0; for (fpos++; !(finfo & INFO_T); fpos++) { if (!format_str[fpos]) { finfo |= INFO_T_ERROR; break; } if (((format_str[fpos] >= '0') && (format_str[fpos] <= '9')) || (format_str[fpos] == '*')) { if (pres == -1) { /* then looking for pres */ if (format_str[fpos] == '*') { if (carg->type != T_NUMBER) ERROR(ERR_INVALID_STAR); pres = carg->u.number; GET_NEXT_ARG; continue; } pres = format_str[fpos] - '0'; for (fpos++; (format_str[fpos] >= '0') && (format_str[fpos] <= '9'); fpos++) { pres = pres * 10 + format_str[fpos] - '0'; } if (pres < 0) pres = 0; } else { /* then is fs (and maybe pres) */ if ((format_str[fpos] == '0') && (((format_str[fpos + 1] >= '1') && (format_str[fpos + 1] <= '9')) || (format_str[fpos + 1] == '*'))) { pad.what = "0"; pad.len = 1; } else { if (format_str[fpos] == '*') { if (carg->type != T_NUMBER) ERROR(ERR_INVALID_STAR); fs = carg->u.number; if (fs < 0) fs = 0; if (pres == -2) pres = fs; /* colon */ GET_NEXT_ARG; continue; } fs = format_str[fpos] - '0'; } for (fpos++; (format_str[fpos] >= '0') && (format_str[fpos] <= '9'); fpos++) { fs = fs * 10 + format_str[fpos] - '0'; } if (fs < 0) fs = 0; if (pres == -2) { /* colon */ pres = fs; } } fpos--; /* about to get incremented */ continue; } switch (format_str[fpos]) { case ' ': finfo |= INFO_PP_SPACE; break; case '+': finfo |= INFO_PP_PLUS; break; case '-': finfo |= INFO_J_LEFT; break; case '|': finfo |= INFO_J_CENTRE; break; case '@': finfo |= INFO_ARRAY; break; case '=': finfo |= INFO_COLS; break; case '#': finfo |= INFO_TABLE; break; case '.': pres = -1; break; case ':': pres = -2; break; #ifdef DEBUG case '%': finfo |= INFO_T_NULL; break; /* never reached */ #endif case 'O': finfo |= INFO_T_LPC; break; case 's': finfo |= INFO_T_STRING; break; case 'd': case 'i': finfo |= INFO_T_INT; break; case 'f': finfo |= INFO_T_FLOAT; break; case 'c': finfo |= INFO_T_CHAR; break; case 'o': finfo |= INFO_T_OCT; break; case 'x': finfo |= INFO_T_HEX; break; case 'X': finfo |= INFO_T_C_HEX; break; case '\'': fpos++; pad.what = format_str + fpos; while (1) { if (!format_str[fpos]) ERROR(ERR_UNEXPECTED_EOS); if (format_str[fpos] == '\\') { if (!format_str[++fpos]) ERROR(ERR_UNEXPECTED_EOS); } else if (format_str[fpos] == '\'') { pad.len = format_str + fpos - pad.what; if (!pad.len) ERROR(ERR_NULL_PS); break; } fpos++; } break; default: finfo |= INFO_T_ERROR; } } /* end of for () */ if (pres < 0) ERROR(ERR_PRES_EXPECTED); /* * now handle the different arg types... */ if (finfo & INFO_ARRAY) { if (carg->type != T_ARRAY) ERROR(ERR_ARRAY_EXPECTED); if (carg->u.arr->size == 0) { last = fpos; fpos--; /* 'bout to get incremented */ continue; } carg = (argv + sprintf_state->cur_arg)->u.arr->item; nelemno = 1; /* next element number */ } while (1) { if ((finfo & INFO_T) == INFO_T_LPC) { outbuffer_t outbuf; outbuf_zero(&outbuf); svalue_to_string(carg, &outbuf, 0, 0, 0); outbuf_fix(&outbuf); sprintf_state->clean.type = T_STRING; sprintf_state->clean.subtype = STRING_MALLOC; sprintf_state->clean.u.string = outbuf.buffer; carg = &(sprintf_state->clean); finfo ^= INFO_T_LPC; finfo |= INFO_T_STRING; } if ((finfo & INFO_T) == INFO_T_ERROR) { ERROR(ERR_INVALID_FORMAT_STR); #ifdef DEBUG } else if ((finfo & INFO_T) == INFO_T_NULL) { /* never reached... */ fprintf(stderr, "/%s: (s)printf: INFO_T_NULL.... found.\n", current_object->obname); ADD_CHAR('%'); #endif } else if ((finfo & INFO_T) == INFO_T_STRING) { int slen; /* * %s null handling added 930709 by Luke Mewburn * <*****@*****.**> */ if (carg->type == T_NUMBER && carg->u.number == 0) { sprintf_state->clean.type = T_STRING; sprintf_state->clean.subtype = STRING_MALLOC; sprintf_state->clean.u.string = string_copy(NULL_MSG, "sprintf NULL"); carg = &(sprintf_state->clean); } else if (carg->type != T_STRING) { ERROR(ERR_INCORRECT_ARG_S); } slen = SVALUE_STRLEN(carg); if ((finfo & INFO_COLS) || (finfo & INFO_TABLE)) { cst **temp; if (!fs) { ERROR(ERR_CST_REQUIRES_FS); } temp = &(sprintf_state->csts); while (*temp) temp = &((*temp)->next); if (finfo & INFO_COLS) { int tmp; if (pres > fs) pres = fs; *temp = ALLOCATE(cst, TAG_TEMPORARY, "string_print: 3"); (*temp)->next = 0; (*temp)->d.col = carg->u.string; (*temp)->pad = make_pad(&pad); (*temp)->size = fs; (*temp)->pres = (pres) ? pres : fs; (*temp)->info = finfo; (*temp)->start = get_curpos(); #ifdef TCC puts("tcc has some bugs"); #endif tmp = ((format_str[fpos] != '\n') && (format_str[fpos] != '\0')) || ((finfo & INFO_ARRAY) && (nelemno < (argv + sprintf_state->cur_arg)->u.arr->size)); tmp = add_column(temp, tmp); if (tmp == 2 && !format_str[fpos]) { ADD_CHAR('\n'); } } else {/* (finfo & INFO_TABLE) */ unsigned int n, len, max_len; const char *p1, *p2; #define TABLE carg->u.string (*temp) = ALLOCATE(cst, TAG_TEMPORARY, "string_print: 4"); (*temp)->d.tab = 0; (*temp)->pad = make_pad(&pad); (*temp)->info = finfo; (*temp)->start = get_curpos(); (*temp)->next = 0; max_len = 0; n = 1; p2 = p1 = TABLE; while (*p1) { if (*p1 == '\n') { if (p1 - p2 > max_len) max_len = p1 - p2; p1++; if (*(p2 = p1)) n++; } else p1++; } if (!pres) { /* the null terminated word */ if (p1 - p2 > max_len) max_len = p1 - p2; pres = fs / (max_len + 2); /* at least two * separating spaces */ if (!pres) pres = 1; /* This moves some entries from the right side * of the table to fill out the last line, * which makes the table look a bit nicer. * E.g. * (n=13,p=6) (l=3,p=5) * X X X X X X X X X X X * X X X X X X -> X X X X X * X X X X X * */ len = (n-1)/pres + 1; if (n > pres && n % pres) pres -= (pres - n % pres) / len; } else { len = (n-1)/pres + 1; } (*temp)->size = fs / pres; (*temp)->remainder = fs % pres; if (n < pres) { /* If we have fewer elements than columns, * pretend we are dealing with a smaller * table. */ (*temp)->remainder += (pres - n)*((*temp)->size); pres = n; } (*temp)->d.tab = CALLOCATE(pres + 1, tab_data_t, TAG_TEMPORARY, "string_print: 5"); (*temp)->nocols = pres; /* heavy sigh */ (*temp)->d.tab[0].start = TABLE; if (pres == 1) { (*temp)->d.tab[1].start = TABLE + SVALUE_STRLEN(carg) + 1; } else { i = 1; /* the next column number */ n = 0; /* the current "word" number in this * column */ p1 = TABLE; while (*p1) { if (*p1++ == '\n' && ++n >= len) { (*temp)->d.tab[i++].start = p1; n = 0; } } for ( ; i <= pres; i++) (*temp)->d.tab[i].start = ++p1; } for (i = 0; i < pres; i++) (*temp)->d.tab[i].cur = (*temp)->d.tab[i].start; add_table(temp); } } else { /* not column or table */ const char *tmp = carg->u.string; //work around tcc bug; if (pres && pres < slen) slen = pres; add_justified(tmp, slen, &pad, fs, finfo, (((format_str[fpos] != '\n') && (format_str[fpos] != '\0')) || ((finfo & INFO_ARRAY) && (nelemno < (argv + sprintf_state->cur_arg)->u.arr->size))) || carg->u.string[slen - 1] != '\n'); } } else if (finfo & INFO_T_INT) { /* one of the integer * types */ char cheat[20]; char temp[100]; *cheat = '%'; i = 1; switch (finfo & INFO_PP) { case INFO_PP_SPACE: cheat[i++] = ' '; break; case INFO_PP_PLUS: cheat[i++] = '+'; break; } if (pres) { cheat[i++] = '.'; if(pres >= sizeof(temp)) sprintf(cheat + i, "%ld", sizeof(temp) - 1); else sprintf(cheat + i, "%d", pres); i += strlen(cheat + i); } switch (finfo & INFO_T) { case INFO_T_INT: cheat[i++] = 'l'; cheat[i++] = 'd'; break; case INFO_T_FLOAT: cheat[i++] = 'f'; break; case INFO_T_CHAR: cheat[i++] = 'c'; break; case INFO_T_OCT: cheat[i++] = 'l'; cheat[i++] = 'o'; break; case INFO_T_HEX: cheat[i++] = 'l'; cheat[i++] = 'x'; break; case INFO_T_C_HEX: cheat[i++] = 'l'; cheat[i++] = 'X'; break; default: ERROR(ERR_BAD_INT_TYPE); } if ((cheat[i - 1] == 'f' && carg->type != T_REAL) || (cheat[i - 1] != 'f' && carg->type != T_NUMBER)) { #ifdef RETURN_ERROR_MESSAGES sprintf(buff, "ERROR: (s)printf(): Incorrect argument type to %%%c. (arg: %u)\n", cheat[i - 1], sprintf_state->cur_arg); fprintf(stderr, "Program /%s File: %s: %s", current_prog->name, get_line_number_if_any(), buff); debug_message("%s", buff); if (current_object) { debug_message("program: /%s, object: %s, file: %s\n", current_prog ? current_prog->name : "", current_object->name, get_line_number_if_any()); } ERROR(ERR_RECOVERY_ONLY); #else error("ERROR: (s)printf(): Incorrect argument type to %%%c.\n", cheat[i - 1]); #endif /* RETURN_ERROR_MESSAGES */ } cheat[i] = '\0'; if (carg->type == T_REAL) { sprintf(temp, cheat, carg->u.real); } else sprintf(temp, cheat, carg->u.number); { int tmpl = strlen(temp); add_justified(temp, tmpl, &pad, fs, finfo, (((format_str[fpos] != '\n') && (format_str[fpos] != '\0')) || ((finfo & INFO_ARRAY) && (nelemno < (argv + sprintf_state->cur_arg)->u.arr->size)))); } } else /* type not found */ ERROR(ERR_UNDEFINED_TYPE); if (sprintf_state->clean.type != T_NUMBER) { free_svalue(&(sprintf_state->clean), "string_print_formatted"); sprintf_state->clean.type = T_NUMBER; } if (!(finfo & INFO_ARRAY)) break; if (nelemno >= (argv + sprintf_state->cur_arg)->u.arr->size) break; carg = (argv + sprintf_state->cur_arg)->u.arr->item + nelemno++; } /* end of while (1) */ last = fpos; fpos--; /* bout to get incremented */ } } /* end of for (fpos=0; 1; fpos++) */ outbuf_fix(&sprintf_state->obuff); retvalue = sprintf_state->obuff.buffer; sprintf_state->obuff.buffer = 0; pop_stack(); /* pop off our error handler, will call pop_sprintf_state */ return retvalue; } /* end of string_print_formatted() */