/** * New sprintf implementation for PHP. * * Modifiers: * * " " pad integers with spaces * "-" left adjusted field * n field size * "."n precision (floats only) * "+" Always place a sign (+ or -) in front of a number * * Type specifiers: * * "%" literal "%", modifiers are ignored. * "b" integer argument is printed as binary * "c" integer argument is printed as a single character * "d" argument is an integer * "f" the argument is a float * "o" integer argument is printed as octal * "s" argument is a string * "x" integer argument is printed as lowercase hexadecimal * "X" integer argument is printed as uppercase hexadecimal */ char *string_printf(const char *format, int len, CArrRef args, int *outlen) { Array vargs = args; if (!vargs.isNull() && !vargs->isVectorData()) { vargs = Array::Create(); for (ArrayIter iter(args); iter; ++iter) { vargs.append(iter.second()); } } if (len == 0) { return strdup(""); } int size = 240; char *result = (char *)malloc(size); int outpos = 0; int argnum = 0, currarg = 1; for (int inpos = 0; inpos < len; ++inpos) { char ch = format[inpos]; int expprec = 0; if (ch != '%') { appendchar(&result, &outpos, &size, ch); continue; } if (format[inpos + 1] == '%') { appendchar(&result, &outpos, &size, '%'); inpos++; continue; } /* starting a new format specifier, reset variables */ int alignment = ALIGN_RIGHT; int adjusting = 0; char padding = ' '; int always_sign = 0; int width, precision; inpos++; /* skip the '%' */ ch = format[inpos]; if (isascii(ch) && !isalpha(ch)) { /* first look for argnum */ int temppos = inpos; while (isdigit((int)format[temppos])) temppos++; if (format[temppos] == '$') { argnum = getnumber(format, &inpos); if (argnum <= 0) { free(result); throw_invalid_argument("argnum: must be greater than zero"); return nullptr; } inpos++; /* skip the '$' */ } else { argnum = currarg++; } /* after argnum comes modifiers */ for (;; inpos++) { ch = format[inpos]; if (ch == ' ' || ch == '0') { padding = ch; } else if (ch == '-') { alignment = ALIGN_LEFT; /* space padding, the default */ } else if (ch == '+') { always_sign = 1; } else if (ch == '\'') { padding = format[++inpos]; } else { break; } } ch = format[inpos]; /* after modifiers comes width */ if (isdigit(ch)) { if ((width = getnumber(format, &inpos)) < 0) { free(result); throw_invalid_argument("width: must be greater than zero " "and less than %d", INT_MAX); return nullptr; } adjusting |= ADJ_WIDTH; } else { width = 0; } ch = format[inpos]; /* after width and argnum comes precision */ if (ch == '.') { ch = format[++inpos]; if (isdigit((int)ch)) { if ((precision = getnumber(format, &inpos)) < 0) { free(result); throw_invalid_argument("precision: must be greater than zero " "and less than %d", INT_MAX); return nullptr; } ch = format[inpos]; adjusting |= ADJ_PRECISION; expprec = 1; } else { precision = 0; } } else { precision = 0; } } else { width = precision = 0; argnum = currarg++; } if (argnum > vargs.size()) { free(result); throw_invalid_argument("arguments: (too few)"); return nullptr; } if (ch == 'l') { ch = format[++inpos]; } /* now we expect to find a type specifier */ Variant tmp = vargs[argnum-1]; switch (ch) { case 's': { String s = tmp.toString(); appendstring(&result, &outpos, &size, s.c_str(), width, precision, padding, alignment, s.size(), 0, expprec, 0); break; } case 'd': appendint(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, always_sign); break; case 'u': appenduint(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment); break; case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': appenddouble(&result, &outpos, &size, tmp.toDouble(), width, padding, alignment, precision, adjusting, ch, always_sign); break; case 'c': appendchar(&result, &outpos, &size, tmp.toByte()); break; case 'o': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 3, hexchars, expprec); break; case 'x': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 4, hexchars, expprec); break; case 'X': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 4, HEXCHARS, expprec); break; case 'b': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 1, hexchars, expprec); break; case '%': appendchar(&result, &outpos, &size, '%'); break; default: break; } } /* possibly, we have to make sure we have room for the terminating null? */ result[outpos]=0; if (outlen) *outlen = outpos; return result; }
/* * Do format conversion placing the output in buffer */ static int xbuf_format_converter(char **outbuf, const char *fmt, va_list ap) { register char *s = nullptr; char *q; int s_len; register int min_width = 0; int precision = 0; enum { LEFT, RIGHT } adjust; char pad_char; char prefix_char; double fp_num; wide_int i_num = (wide_int) 0; u_wide_int ui_num; char num_buf[NUM_BUF_SIZE]; char char_buf[2]; /* for printing %% and %<unknown> */ #ifdef HAVE_LOCALE_H struct lconv *lconv = nullptr; #endif /* * Flag variables */ length_modifier_e modifier; boolean_e alternate_form; boolean_e print_sign; boolean_e print_blank; boolean_e adjust_precision; boolean_e adjust_width; int is_negative; int size = 240; char *result = (char *)malloc(size); int outpos = 0; while (*fmt) { if (*fmt != '%') { appendchar(&result, &outpos, &size, *fmt); } else { /* * Default variable settings */ adjust = RIGHT; alternate_form = print_sign = print_blank = NO; pad_char = ' '; prefix_char = NUL; fmt++; /* * Try to avoid checking for flags, width or precision */ if (isascii((int)*fmt) && !islower((int)*fmt)) { /* * Recognize flags: -, #, BLANK, + */ for (;; fmt++) { if (*fmt == '-') adjust = LEFT; else if (*fmt == '+') print_sign = YES; else if (*fmt == '#') alternate_form = YES; else if (*fmt == ' ') print_blank = YES; else if (*fmt == '0') pad_char = '0'; else break; } /* * Check if a width was specified */ if (isdigit((int)*fmt)) { STR_TO_DEC(fmt, min_width); adjust_width = YES; } else if (*fmt == '*') { min_width = va_arg(ap, int); fmt++; adjust_width = YES; if (min_width < 0) { adjust = LEFT; min_width = -min_width; } } else adjust_width = NO; /* * Check if a precision was specified * * XXX: an unreasonable amount of precision may be specified * resulting in overflow of num_buf. Currently we * ignore this possibility. */ if (*fmt == '.') { adjust_precision = YES; fmt++; if (isdigit((int)*fmt)) { STR_TO_DEC(fmt, precision); } else if (*fmt == '*') { precision = va_arg(ap, int); fmt++; if (precision < 0) precision = 0; } else
void handlepencilmsg(cJSON *json, struct user *usr) { struct pencil *p = &usr->pencil; struct buffer buf; char buffer_empty = 1; char mousedown; json = jsongetjson(json, "data"); if (!json) return; json = json->child; p->ticksolid = max(p->ticksolid + 1, usr->gm->tick + SERVER_DELAY / TICK_LENGTH + usr->gm->inkdelay / TICK_LENGTH); /* this will be sent to other players */ buf.start = 0; appendheader(&buf, MODE_PENCIL, usr->index); appendtick(&buf, p->ticksolid); if ((mousedown = json->valueint == -1)) json = json->next; appendchar(&buf, mousedown); assert(!pthread_mutex_lock(&usr->gm->lock)); while (json) { int x, y, tick; if (!readpencilmsg(&json, &x, &y, &tick)) break; if (tick < p->tick || x < 0 || y < 0 || x > usr->gm->w || y > usr->gm->h) break; if (abs(usr->gm->tick + SERVER_DELAY / TICK_LENGTH - tick) > MAX_LAG_SPIKE / TICK_LENGTH) { warningplayer(usr, "error: tick of pencil msg not valid\n"); break; } regenink(p, tick); if (mousedown) { if (p->ink < MOUSEDOWN_INK) { warningplayer(usr, "error: not enough ink for pencil down. %d required, %f left\n", MOUSEDOWN_INK, p->ink); break; } p->ink -= MOUSEDOWN_INK; p->down = 1; mousedown = 0; } else { double d = getlength(p->x - x, p->y - y); if (!p->down) { warningplayer(usr, "error: pencil move: pencil not down\n"); break; } if (p->ink < d) { warningplayer(usr, "error: pencil move: not enough ink. %f required, %f left\n", d, p->ink); break; } if (d < INK_MIN_DISTANCE) p->down = 0; if (p->x == x && p->y == y) break; p->ink -= d; queuepencilseg(p, x, y); } appendpos(&buf, x, y); p->x = x; p->y = y; buffer_empty = 0; } if (!buffer_empty) airstr(buf.start, buf.at - buf.start, usr->gm, 0); pthread_mutex_unlock(&usr->gm->lock); free(buf.start); }