📄 visitors.c
字号:
/* Returns true if 'year' is a leap year. */int isleap(int year){ int conda, condb, condc; conda = (year%4) == 0; condb = (year%100) == 0; condc = (year%400) == 0; return conda && !(condb && !condc);}#endif/* URL decoding and white spaces trimming function. * Input: the encoded string 's'. * Output: the decoded string written at 'd' that has room for at least 'n' * bytes of data. */void vi_urldecode(char *d, char *s, int n){ char *start = d; if (n < 1) return; while(*s && n > 1) { int c = *s; switch(c) { case '+': c = ' '; break; case '%': if (*(s+1) && *(s+2)) { int high = toupper(*(s+1)); int low = toupper(*(s+2)); if (high <= '9') high -= '0'; else high = (high - 'A') + 10; if (low <= '9') low -= '0'; else low = (low - 'A') + 10; c = (high << 4)+low; s += 2; } break; } if (c != ' ' || d != start) { *d++ = c; n--; } s++; } /* Right trim */ *d = '\0'; d--; while (d >= start && *d == ' ') { *d = '\0'; d--; }}/* URL encoding function * Input: the unencoded string 's'. * Output: the url-encoded string written at 'd' that has room for at least 'n' * bytes of data. */void vi_urlencode(char *d, char *s, int n){ if (n < 1) return; n--; while(*s && n > 0) { int c = *s; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { *d++ = c; n--; } else if (c == ' ') { *d++ = '+'; n--; } else if (c == '\n') { if (n < 6) break; memcpy(d, "%0d%0a", 6); d += 6; n -= 6; } else { unsigned int t; char *hexset = "0123456789abcdef"; if (n < 3) break; t = (unsigned) c; *d++ = '%'; *d++ = hexset [(t & 0xF0) >> 4]; *d++ = hexset [(t & 0x0F)]; n -= 3; } s++; } *d = '\0';}/* Convert a nul-term string to lowercase in place */void vi_strtolower(char *s){ while (*s) { *s = tolower(*s); s++; }}/* Note: the following function strlcat and strlcpy are (possibly) modified * version of OpenBSD's functions. Original copyright notice: * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> * Originally under the BSD license. */int vi_strlcpy(char *dst, char *src, int siz){ char *d = dst; const char *s = src; int n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */}int vi_strlcat(char *dst, const char *src, int siz){ char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */}/* Returns non-zero if the url matches one of the keywords in * blacklist.h, otherwise zero is returned. Warning!!! This function * run time is proportional to the size of blacklist.h, so it is * very slow. */int vi_is_blacklisted_url(struct vih *vih, char *url){ unsigned int i; for (i = 0; i < VI_BLACKLIST_LEN; i++) { if (strstr(url, vi_blacklist[i])) { vih->blacklisted++; return 1; } } return 0;}/* Glob-style pattern matching. */int vi_match_len(const char *pattern, int patternLen, const char *string, int stringLen, int nocase){ while(patternLen) { switch(pattern[0]) { case '*': while (pattern[1] == '*') { pattern++; patternLen--; } if (patternLen == 1) return 1; /* match */ while(stringLen) { if (vi_match_len(pattern+1, patternLen-1, string, stringLen, nocase)) return 1; /* match */ string++; stringLen--; } return 0; /* no match */ break; case '?': if (stringLen == 0) return 0; /* no match */ string++; stringLen--; break; case '[': { int not, match; pattern++; patternLen--; not = pattern[0] == '^'; if (not) { pattern++; patternLen--; } match = 0; while(1) { if (pattern[0] == '\\') { pattern++; patternLen--; if (pattern[0] == string[0]) match = 1; } else if (pattern[0] == ']') { break; } else if (patternLen == 0) { pattern--; patternLen++; break; } else if (pattern[1] == '-' && patternLen >= 3) { int start = pattern[0]; int end = pattern[2]; int c = string[0]; if (start > end) { int t = start; start = end; end = t; } if (nocase) { start = tolower(start); end = tolower(end); c = tolower(c); } pattern += 2; patternLen -= 2; if (c >= start && c <= end) match = 1; } else { if (!nocase) { if (pattern[0] == string[0]) match = 1; } else { if (tolower((int)pattern[0]) == tolower((int)string[0])) match = 1; } } pattern++; patternLen--; } if (not) match = !match; if (!match) return 0; /* no match */ string++; stringLen--; break; } case '\\': if (patternLen >= 2) { pattern++; patternLen--; } /* fall through */ default: if (!nocase) { if (pattern[0] != string[0]) return 0; /* no match */ } else { if (tolower((int)pattern[0]) != tolower((int)string[0])) return 0; /* no match */ } string++; stringLen--; break; } pattern++; patternLen--; if (stringLen == 0) { while(*pattern == '*') { pattern++; patternLen--; } break; } } if (patternLen == 0 && stringLen == 0) return 1; return 0;}/* Like vi_match_len but more handly if used against nul-term strings. */int vi_match(const char *pattern, const char *string, int nocase){ int patternLen = strlen(pattern); int stringLen = strlen(string); return vi_match_len(pattern, patternLen, string, stringLen, nocase);}/*-------------------------- visitors handler functions --------------------- *//* Init the hashtable with methods suitable for an "occurrences counter" */void vi_ht_init(struct hashtable *ht){ ht_init(ht); ht_set_hash(ht, ht_hash_string); ht_set_key_destructor(ht, ht_destructor_free); ht_set_val_destructor(ht, ht_no_destructor); ht_set_key_compare(ht, ht_compare_string);}/* Reset the weekday/hour info in the visitors handler. */void vi_reset_combined_maps(struct vih *vih){ int i, j; for (i = 0; i < 24; i++) { vih->hour[i] = 0; for (j = 0; j < 7; j++) vih->weekdayhour[j][i] = 0; } for (i = 0; i < 7; i++) vih->weekday[i] = 0; for (i = 0; i < 31; i++) for (j = 0; j < 12; j++) vih->monthday[j][i] = 0;}/* Reset the hashtables from the handler, that are left * in a reusable state (but all empty). */void vi_reset_hashtables(struct vih *vih){ ht_destroy(&vih->visitors); ht_destroy(&vih->googlevisitors); ht_destroy(&vih->pages); ht_destroy(&vih->images); ht_destroy(&vih->error404); ht_destroy(&vih->pageviews); ht_destroy(&vih->pageviews_grouped); ht_destroy(&vih->referers); ht_destroy(&vih->referersage); ht_destroy(&vih->agents); ht_destroy(&vih->googled); ht_destroy(&vih->adsensed); ht_destroy(&vih->googlekeyphrases); ht_destroy(&vih->googlekeyphrasesage); ht_destroy(&vih->googlevisits); ht_destroy(&vih->trails); ht_destroy(&vih->tld); ht_destroy(&vih->os); ht_destroy(&vih->browsers); ht_destroy(&vih->date); ht_destroy(&vih->googledate); ht_destroy(&vih->month); ht_destroy(&vih->googlemonth); ht_destroy(&vih->robots); ht_destroy(&vih->googlehumanlanguage); ht_destroy(&vih->screenres); ht_destroy(&vih->screendepth);}/* Reset handler informations to support --reset option in * stream mode. */void vi_reset(struct vih *vih){ vi_reset_combined_maps(vih); vi_reset_hashtables(vih);}/* Return a new visitors handle. * On out of memory NULL is returned. * The handle obtained with this call must be released with vi_free() * when no longer useful. */struct vih *vi_new(void){ struct vih *vih; if ((vih = malloc(sizeof(*vih))) == NULL) return NULL; /* Initialization */ vih->startt = vih->endt = time(NULL); vih->processed = 0; vih->invalid = 0; vih->blacklisted = 0; vi_reset_combined_maps(vih); vih->error = NULL; vi_ht_init(&vih->visitors); vi_ht_init(&vih->googlevisitors); vi_ht_init(&vih->pages); vi_ht_init(&vih->images); vi_ht_init(&vih->error404); vi_ht_init(&vih->pageviews); vi_ht_init(&vih->pageviews_grouped); vi_ht_init(&vih->referers); vi_ht_init(&vih->referersage); vi_ht_init(&vih->agents); vi_ht_init(&vih->googled); vi_ht_init(&vih->adsensed); vi_ht_init(&vih->googlevisits); vi_ht_init(&vih->googlekeyphrases); vi_ht_init(&vih->googlekeyphrasesage); vi_ht_init(&vih->trails); vi_ht_init(&vih->tld); vi_ht_init(&vih->os); vi_ht_init(&vih->browsers); vi_ht_init(&vih->date); vi_ht_init(&vih->month); vi_ht_init(&vih->googledate); vi_ht_init(&vih->googlemonth); vi_ht_init(&vih->robots); vi_ht_init(&vih->googlehumanlanguage); vi_ht_init(&vih->screenres); vi_ht_init(&vih->screendepth); return vih;}/* Free an handle created with vi_new(). */void vi_free(struct vih *vih){ if (!vih) return; vi_reset_hashtables(vih); vi_clear_error(vih); free(vih);}/* Add a new entry in the counter hashtable. If the key does not * exists creates a new entry with "1" as number of hits, otherwise * increment the old value. * * Return the value of hits after the increment or creation. If the * returned value is greater than one, the key was already seen. * * Return 0 on out of memory. * * NOTE: the pointer of the "value" part of the hashtable entry is * used as a counter casting it to a "long" integer. */int vi_counter_incr(struct hashtable *ht, char *key){ char *k; unsigned int idx; int r; long val; r = ht_search(ht, key, &idx); if (r == HT_NOTFOUND) { k = strdup(key); if (k == NULL) return 0; if (ht_add(ht, k, (void*)1) != HT_OK) { free(k); return 0; } return 1; } else { val = (long) ht_value(ht, idx); val++; ht_value(ht, idx) = (void*) val; return val; }}/* Similar to vi_counter_incr, but only read the old value of * the counter without to alter it. If the specified key does not * exists zero is returned. */int vi_counter_val(struct hashtable *ht, char *key){ unsigned int idx; int r; long val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -