+static inline PSI_Token *PSI_TokenCat(unsigned argc, ...) {
+ va_list argv;
+ unsigned i;
+ PSI_Token *T = NULL;
+
+ va_start(argv, argc);
+ for (i = 0; i < argc; ++i) {
+ PSI_Token *arg = va_arg(argv, PSI_Token *);
+
+ if (T) {
+ size_t token_len = T->size, fname_len = strlen(T->file);
+
+ T = realloc(T, PSI_TokenAllocSize(T->size += arg->size + 1, fname_len));
+ T->text = &T->buf[0];
+ T->file = &T->buf[T->size + 1];
+ T->buf[token_len] = ' ';
+ memmove(&T->buf[T->size + 1], &T->buf[token_len + 1], fname_len + 1);
+ memcpy(&T->buf[token_len + 1], arg->text, arg->size + 1);
+ } else {
+ T = PSI_TokenCopy(arg);
+ T->type = PSI_T_NAME;
+ }
+ }
+ va_end(argv);
+
+ return T;
+}
+
+static inline PSI_Token *PSI_TokenAppend(PSI_Token *T, unsigned argc, ...) {
+ va_list argv;
+ unsigned i;
+
+ va_start(argv, argc);
+ for (i = 0; i < argc; ++i) {
+ char *str = va_arg(argv, char *);
+ size_t str_len = strlen(str), token_len = T->size, fname_len = strlen(T->file);
+
+ T = realloc(T, PSI_TokenAllocSize(T->size += str_len + 1, fname_len));
+ T->text = &T->buf[0];
+ T->file = &T->buf[T->size + 1];
+ T->buf[token_len] = ' ';
+ memmove(&T->buf[T->size + 1], &T->buf[token_len + 1], fname_len + 1);
+ memcpy(&T->buf[token_len + 1], str, str_len + 1);
+ }
+ va_end(argv);
+
+ return T;
+}
+
+char *php_strtr(char *str, size_t len, char *str_from, char *str_to, size_t trlen);
+static inline PSI_Token *PSI_TokenTranslit(PSI_Token *T, char *from, char *to) {
+ php_strtr(T->text, T->size, from, to, MIN(strlen(from), strlen(to)));
+ return T;
+}
+
+static inline uint64_t psi_hash(char *digest_buf, ...)
+{
+ uint64_t hash = 5381;
+ uint8_t c;
+ const uint8_t *ptr;
+ va_list argv;
+
+ va_start(argv, digest_buf);
+ while ((ptr = va_arg(argv, const uint8_t *))) {
+ while ((c = *ptr++)) {
+ hash = ((hash << 5) + hash) + c;
+ }
+ }
+ va_end(argv);
+
+ if (digest_buf) {
+ sprintf(digest_buf, "%" PRIx64, hash);
+ }
+
+ return hash;
+}
+
+static inline uint64_t PSI_TokenHash(PSI_Token *t, char *digest_buf) {
+ char loc_buf[48];
+
+ sprintf(loc_buf, "%u%u", t->line, t->col);
+ return psi_hash(digest_buf, t->file, loc_buf, NULL);
+}
+