summaryrefslogtreecommitdiffstats
path: root/src/libbbsutil/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libbbsutil/string.c')
-rw-r--r--src/libbbsutil/string.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/libbbsutil/string.c b/src/libbbsutil/string.c
new file mode 100644
index 00000000..695d65ab
--- /dev/null
+++ b/src/libbbsutil/string.c
@@ -0,0 +1,284 @@
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include "fnv_hash.h"
+
+#include "ansi.h"
+#include "libbbsutil.h"
+
+#define CHAR_LOWER(c) ((c >= 'A' && c <= 'Z') ? c|32 : c)
+/* ----------------------------------------------------- */
+/* 字串轉換檢查函數 */
+/* ----------------------------------------------------- */
+/**
+ * 將字串 s 轉為小寫存回 t
+ * @param t allocated char array
+ * @param s
+ */
+void
+str_lower(char *t, const char *s)
+{
+ register unsigned char ch;
+
+ do {
+ ch = *s++;
+ *t++ = CHAR_LOWER(ch);
+ } while (ch);
+}
+
+/**
+ * 移除字串 buf 後端多餘的空白。
+ * @param buf
+ */
+void
+trim(char *buf)
+{ /* remove trailing space */
+ char *p = buf;
+
+ while (*p)
+ p++;
+ while (--p >= buf) {
+ if (*p == ' ')
+ *p = '\0';
+ else
+ break;
+ }
+}
+
+/**
+ * 移除 src 的 '\n' 並改成 '\0'
+ * @param src
+ */
+void chomp(char *src)
+{
+ while(*src){
+ if (*src == '\n')
+ *src = 0;
+ else
+ src++;
+ }
+}
+
+int
+strip_blank(char *cbuf, char *buf)
+{
+ for (; *buf; buf++)
+ if (*buf != ' ')
+ *cbuf++ = *buf;
+ *cbuf = 0;
+ return 0;
+}
+
+static const char EscapeFlag[] = {
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0,
+ /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, /* 0~9 ;= */
+ /* 40 */ 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, /* ABCDHIJK */
+ /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 60 */ 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 2, 0, 0, /* fhlm */
+ /* 70 */ 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* su */
+ /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+/**
+ * 根據 mode 來 strip 字串 src,並把結果存到 dst
+ * @param dst
+ * @param src
+ * @param mode enum {STRIP_ALL = 0, ONLY_COLOR, NO_RELOAD};
+ * STRIP_ALL: 全部吃掉
+ * ONLY_COLOR: 吃掉所有跟顏色無關的 (ESC[*m)
+ * NO_RELOAD: 不 strip (?)
+ * @return strip 後的長度
+ */
+int
+strip_ansi(char *dst, const char *src, enum STRIP_FLAG mode)
+{
+ register int count = 0;
+#define isEscapeParam(X) (EscapeFlag[(int)(X)] & 1)
+#define isEscapeCommand(X) (EscapeFlag[(int)(X)] & 2)
+
+ for(; *src; ++src)
+ if( *src != ESC_CHR ){
+ if( dst )
+ *dst++ = *src;
+ ++count;
+ }else{
+ const char* p = src + 1;
+ if( *p != '[' ){
+ ++src;
+ if(*src=='\0') break;
+ continue;
+ }
+ while(isEscapeParam(*++p));
+ if( (mode == NO_RELOAD && isEscapeCommand(*p)) ||
+ (mode == ONLY_COLOR && *p == 'm' )){
+ register int len = p - src + 1;
+ if( dst ){
+ strncpy(dst, src, len);
+ dst += len;
+ }
+ count += len;
+ }
+ src = p;
+ if(*src=='\0') break;
+ }
+ if( dst )
+ *dst = 0;
+ return count;
+}
+
+int
+strlen_noansi(const char *s)
+{
+ // XXX this is almost identical to
+ // strip_ansi(NULL, s, STRIP_ALL)
+ register int count = 0, mode = 0;
+
+ if (!s || !*s)
+ return 0;
+
+ for (; *s; ++s)
+ {
+ // 0 - no ansi, 1 - [, 2 - param+cmd
+ switch (mode)
+ {
+ case 0:
+ if (*s == ESC_CHR)
+ mode = 1;
+ else
+ count ++;
+ break;
+
+ case 1:
+ if (*s == '[')
+ mode = 2;
+ else
+ mode = 0; // unknown command
+ break;
+
+ case 2:
+ if (isEscapeParam(*s))
+ continue;
+ else if (isEscapeCommand(*s))
+ mode = 0;
+ else
+ mode = 0;
+ break;
+ }
+ }
+ return count;
+}
+
+void
+strip_nonebig5(unsigned char *str, int maxlen)
+{
+ int i;
+ int len=0;
+ for(i=0;i<maxlen && str[i];i++) {
+ if(32<=str[i] && str[i]<128)
+ str[len++]=str[i];
+ else if(str[i]==255) {
+ if(i+1<maxlen)
+ if(251<=str[i+1] && str[i+1]<=254) {
+ i++;
+ if(i+1<maxlen && str[i+1])
+ i++;
+ }
+ continue;
+ } else if(str[i]&0x80) {
+ if(i+1<maxlen)
+ if((0x40<=str[i+1] && str[i+1]<=0x7e) ||
+ (0xa1<=str[i+1] && str[i+1]<=0xfe)) {
+ str[len++]=str[i];
+ str[len++]=str[i+1];
+ i++;
+ }
+ }
+ }
+ if(len<maxlen)
+ str[len]='\0';
+}
+
+/* ----------------------------------------------------- */
+/* 字串檢查函數:英文、數字、檔名、E-mail address */
+/* ----------------------------------------------------- */
+
+int
+invalid_pname(const char *str)
+{
+ const char *p1, *p2, *p3;
+
+ p1 = str;
+ while (*p1) {
+ if (!(p2 = strchr(p1, '/')))
+ p2 = str + strlen(str);
+ if (p1 + 1 > p2 || p1 + strspn(p1, ".") == p2) /* 不允許用 / 開頭, 或是 // 之間只有 . */
+ return 1;
+ for (p3 = p1; p3 < p2; p3++)
+ if (!isalnum(*p3) && !strchr("@[]-._", *p3)) /* 只允許 alnum 或這些符號 */
+ return 1;
+ p1 = p2 + (*p2 ? 1 : 0);
+ }
+ return 0;
+}
+
+/*
+ * return 1 if /^[0-9]+$/
+ * 0 else, 含空字串
+ */
+int is_number(const char *p)
+{
+ if (*p == '\0')
+ return 0;
+
+ for(; *p; p++) {
+ if (*p < '0' || '9' < *p)
+ return 0;
+ }
+ return 1;
+}
+
+unsigned
+StringHash(const char *s)
+{
+ return fnv1a_32_strcase(s, FNV1_32_INIT);
+}
+
+/* qp_encode() modified from mutt-1.5.7/rfc2047.c q_encoder() */
+const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";
+char * qp_encode (char *s, size_t slen, const char *d, const char *tocode)
+{
+ char hex[] = "0123456789ABCDEF";
+ char *s0 = s;
+
+ memcpy (s, "=?", 2), s += 2;
+ memcpy (s, tocode, strlen (tocode)), s += strlen (tocode);
+ memcpy (s, "?Q?", 3), s += 3;
+ assert(s-s0+3<slen);
+
+ while (*d != '\0' && s-s0+6<slen)
+ {
+ unsigned char c = *d++;
+ if (c == ' ')
+ *s++ = '_';
+ else if (c >= 0x7f || c < 0x20 || c == '_' || strchr (MimeSpecials, c))
+ {
+ *s++ = '=';
+ *s++ = hex[(c & 0xf0) >> 4];
+ *s++ = hex[c & 0x0f];
+ }
+ else
+ *s++ = c;
+ }
+ memcpy (s, "?=", 2), s += 2;
+ *s='\0';
+ return s0;
+}
+