📄 formatting.c
字号:
return;}/* ---------- * Format parser, search small keywords and keyword's suffixes, and make * format-node tree. * * for DATE-TIME & NUMBER version * ---------- */static voidparse_format(FormatNode *node, char *str, const KeyWord *kw, KeySuffix *suf, const int *index, int ver, NUMDesc *Num){ KeySuffix *s; FormatNode *n; int node_set = 0, suffix, last = 0;#ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "to_char/number(): run parser");#endif n = node; while (*str) { suffix = 0; /* * Prefix */ if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL) { suffix |= s->id; if (s->len) str += s->len; } /* * Keyword */ if (*str && (n->key = index_seq_search(str, kw, index)) != NULL) { n->type = NODE_TYPE_ACTION; n->suffix = 0; node_set = 1; if (n->key->len) str += n->key->len; /* * NUM version: Prepare global NUMDesc struct */ if (ver == NUM_TYPE) NUMDesc_prepare(Num, n); /* * Postfix */ if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL) { suffix |= s->id; if (s->len) str += s->len; } } else if (*str) { /* * Special characters '\' and '"' */ if (*str == '"' && last != '\\') { int x = 0; while (*(++str)) { if (*str == '"' && x != '\\') { str++; break; } else if (*str == '\\' && x != '\\') { x = '\\'; continue; } n->type = NODE_TYPE_CHAR; n->character = *str; n->key = NULL; n->suffix = 0; ++n; x = *str; } node_set = 0; suffix = 0; last = 0; } else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"') { last = *str; str++; } else if (*str) { n->type = NODE_TYPE_CHAR; n->character = *str; n->key = NULL; node_set = 1; last = 0; str++; } } /* end */ if (node_set) { if (n->type == NODE_TYPE_ACTION) n->suffix = suffix; ++n; n->suffix = 0; node_set = 0; } } n->type = NODE_TYPE_END; n->suffix = 0; return;}/* ---------- * Call keyword's function for each of (action) node in format-node tree * ---------- */static char *DCH_processor(FormatNode *node, char *inout, bool is_to_char, bool is_interval, void *data){ FormatNode *n; char *s; /* * Zeroing global flags */ DCH_global_fx = false; for (n = node, s = inout; n->type != NODE_TYPE_END; n++) { if (!is_to_char && *s == '\0') /* * The input string is shorter than format picture, so it's good * time to break this loop... * * Note: this isn't relevant for TO_CHAR mode, beacuse it use * 'inout' allocated by format picture length. */ break; if (n->type == NODE_TYPE_ACTION) { int len; /* * Call node action function */ len = n->key->action(n->key->id, s, n->suffix, is_to_char, is_interval, n, data); if (len > 0) s += len - 1; /* s++ is at the end of the loop */ else if (len == -1) continue; } else { /* * Remove to output char from input in TO_CHAR */ if (is_to_char) *s = n->character; else { /* * Skip blank space in FROM_CHAR's input */ if (isspace((unsigned char) n->character) && !DCH_global_fx) while (*s != '\0' && isspace((unsigned char) *(s + 1))) ++s; } } ++s; } if (is_to_char) *s = '\0'; return inout;}/* ---------- * DEBUG: Dump the FormatNode Tree (debug) * ---------- */#ifdef DEBUG_TO_FROM_CHAR#define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " "))#define DUMP_FM(_suf) (S_FM(_suf) ? "FM" : " ")static voiddump_node(FormatNode *node, int max){ FormatNode *n; int a; elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT"); for (a = 0, n = node; a <= max; n++, a++) { if (n->type == NODE_TYPE_ACTION) elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)", a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix)); else if (n->type == NODE_TYPE_CHAR) elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character); else if (n->type == NODE_TYPE_END) { elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a); return; } else elog(DEBUG_elog_output, "%d:\t unknown NODE!", a); }}#endif /* DEBUG *//***************************************************************************** * Private utils *****************************************************************************//* ---------- * Return ST/ND/RD/TH for simple (1..9) numbers * type --> 0 upper, 1 lower * ---------- */static char *get_th(char *num, int type){ int len = strlen(num), last, seclast; last = *(num + (len - 1)); if (!isdigit((unsigned char) last)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%s\" is not a number", num))); /* * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get * 'ST/st', 'ND/nd', 'RD/rd', respectively */ if ((len > 1) && ((seclast = num[len - 2]) == '1')) last = 0; switch (last) { case '1': if (type == TH_UPPER) return numTH[0]; return numth[0]; case '2': if (type == TH_UPPER) return numTH[1]; return numth[1]; case '3': if (type == TH_UPPER) return numTH[2]; return numth[2]; default: if (type == TH_UPPER) return numTH[3]; return numth[3]; } return NULL;}/* ---------- * Convert string-number to ordinal string-number * type --> 0 upper, 1 lower * ---------- */static char *str_numth(char *dest, char *num, int type){ if (dest != num) strcpy(dest, num); strcat(dest, get_th(num, type)); return dest;}/* ---------- * Convert string to upper-string. Input string is modified in place. * ---------- */static char *str_toupper(char *buff){ char *p_buff = buff; if (!buff) return NULL; while (*p_buff) { *p_buff = pg_toupper((unsigned char) *p_buff); ++p_buff; } return buff;}/* ---------- * Convert string to lower-string. Input string is modified in place. * ---------- */static char *str_tolower(char *buff){ char *p_buff = buff; if (!buff) return NULL; while (*p_buff) { *p_buff = pg_tolower((unsigned char) *p_buff); ++p_buff; } return buff;}/* ---------- * Sequential search with to upper/lower conversion * ---------- */static intseq_search(char *name, char **array, int type, int max, int *len){ char *p, *n, **a; int last, i; *len = 0; if (!*name) return -1; /* set first char */ if (type == ONE_UPPER || type == ALL_UPPER) *name = pg_toupper((unsigned char) *name); else if (type == ALL_LOWER) *name = pg_tolower((unsigned char) *name); for (last = 0, a = array; *a != NULL; a++) { /* comperate first chars */ if (*name != **a) continue; for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++) { /* search fragment (max) only */ if (max && i == max) { *len = i; return a - array; } /* full size */ if (*p == '\0') { *len = i; return a - array; } /* Not found in array 'a' */ if (*n == '\0') break; /* * Convert (but convert new chars only) */ if (i > last) { if (type == ONE_UPPER || type == ALL_LOWER) *n = pg_tolower((unsigned char) *n); else if (type == ALL_UPPER) *n = pg_toupper((unsigned char) *n); last = i; }#ifdef DEBUG_TO_FROM_CHAR /* * elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)", *n, *p, *a, * name); */#endif if (*n != *p) break; } } return -1;}#ifdef DEBUG_TO_FROM_CHAR/* ----------- * DEBUG: Call for debug and for index checking; (Show ASCII char * and defined keyword for each used position * ---------- */static voiddump_index(const KeyWord *k, const int *index){ int i, count = 0, free_i = 0; elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:"); for (i = 0; i < KeyWord_INDEX_SIZE; i++) { if (index[i] != -1) { elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name); count++; } else { free_i++; elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]); } } elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d", count, free_i);}#endif /* DEBUG *//* ---------- * Skip TM / th in FROM_CHAR * ---------- */#define SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0)/* ---------- * Global format option for DCH version * ---------- */static intdch_global(int arg, char *inout, int suf, bool is_to_char, bool is_interval, FormatNode *node, void *data){ if (arg == DCH_FX) DCH_global_fx = true; return -1;}/* ---------- * Return TRUE if next format picture is not digit value * ---------- */static boolis_next_separator(FormatNode *n){ if (n->type == NODE_TYPE_END) return FALSE; if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix)) return TRUE; /* * Next node */ n++; if (n->type == NODE_TYPE_END) return FALSE; if (n->type == NODE_TYPE_ACTION) { if (n->key->isitdigit) return FALSE; return TRUE; } else if (isdigit((unsigned char) n->character)) return FALSE; return TRUE; /* some non-digit input (separator) */}static intstrdigits_len(char *str){ char *p = str; int len = 0; while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ) { len++; p++; } return len;}#define AMPM_ERROR ereport(ERROR, \ (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \ errmsg("invalid AM/PM string")));/* ---------- * Master function of TIME for: * TO_CHAR - write (inout) formated string * FROM_CHAR - scan (inout) string by course of FormatNode * ---------- */static intdch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval, FormatNode *node, void *data){ char *p_inout = inout; struct pg_tm *tm = NULL; TmFromChar *tmfc = NULL; TmToChar *tmtc = NULL; if (is_to_char) { tmtc = (TmToChar *) data; tm = tmtcTm(tmtc); } else tmfc = (TmFromChar *) data; switch (arg) { case DCH_A_M: case DCH_P_M: if (is_to_char) { strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2) ? P_M_STR : A_M_STR); return strlen(p_inout); } else { if (strncmp(inout, P_M_STR, 4) == 0) tmfc->pm = TRUE; else if (strncmp(inout, A_M_STR, 4) == 0) tmfc->am = TRUE; else AMPM_ERROR; return strlen(p_inout); } break; case DCH_AM: case DCH_PM: if (is_to_char) { strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2) ? PM_STR : AM_STR); return strlen(p_inout);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -