From 5b243f3204f3edb93e09e8cea8c2f66ac50e00ac Mon Sep 17 00:00:00 2001 From: Richard Russon Date: Thu, 5 Oct 2017 02:11:50 +0100 Subject: [PATCH] move functions to library These functions have no NeoMutt dependencies: * imap_make_date() * imap_parse_date() * imap_wordcasecmp() * rstrnstr() Moving the functions to the library will make it easier to test them and find common behaviour. --- imap/imap_private.h | 3 -- imap/message.c | 2 +- imap/util.c | 91 --------------------------------------------- init.c | 26 ------------- lib/date.c | 77 ++++++++++++++++++++++++++++++++++++++ lib/date.h | 16 ++++---- lib/string.c | 66 ++++++++++++++++++++++++++++++++ lib/string2.h | 2 + 8 files changed, 155 insertions(+), 128 deletions(-) diff --git a/imap/imap_private.h b/imap/imap_private.h index 19a5a7de0..ad4bf0bc1 100644 --- a/imap/imap_private.h +++ b/imap/imap_private.h @@ -324,14 +324,11 @@ int imap_get_literal_count(const char *buf, long *bytes); char *imap_get_qualifier(char *buf); int imap_mxcmp(const char *mx1, const char *mx2); char *imap_next_word(char *s); -time_t imap_parse_date(char *s); -void imap_make_date(char *buf, time_t timestamp); void imap_qualify_path(char *dest, size_t len, struct ImapMbox *mx, char *path); void imap_quote_string(char *dest, size_t slen, const char *src); void imap_unquote_string(char *s); void imap_munge_mbox_name(struct ImapData *idata, char *dest, size_t dlen, const char *src); void imap_unmunge_mbox_name(struct ImapData *idata, char *s); -int imap_wordcasecmp(const char *a, const char *b); /* utf7.c */ void imap_utf_encode(struct ImapData *idata, char **s); diff --git a/imap/message.c b/imap/message.c index 58b3b19e5..83e85821b 100644 --- a/imap/message.c +++ b/imap/message.c @@ -1124,7 +1124,7 @@ int imap_append_message(struct Context *ctx, struct Message *msg) MUTT_PROGRESS_SIZE, NetInc, len); imap_munge_mbox_name(idata, mbox, sizeof(mbox), mailbox); - imap_make_date(internaldate, msg->received); + imap_make_date(internaldate, sizeof(internaldate), msg->received); imap_flags[0] = imap_flags[1] = 0; if (msg->flags.read) diff --git a/imap/util.c b/imap/util.c index baa29d2c4..195071b69 100644 --- a/imap/util.c +++ b/imap/util.c @@ -678,73 +678,6 @@ char *imap_next_word(char *s) return s; } -/** - * imap_parse_date - Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz - */ -time_t imap_parse_date(char *s) -{ - struct tm t; - time_t tz; - - t.tm_mday = (s[0] == ' ' ? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0')); - s += 2; - if (*s != '-') - return 0; - s++; - t.tm_mon = mutt_check_month(s); - s += 3; - if (*s != '-') - return 0; - s++; - t.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + - (s[3] - '0') - 1900; - s += 4; - if (*s != ' ') - return 0; - s++; - - /* time */ - t.tm_hour = (s[0] - '0') * 10 + (s[1] - '0'); - s += 2; - if (*s != ':') - return 0; - s++; - t.tm_min = (s[0] - '0') * 10 + (s[1] - '0'); - s += 2; - if (*s != ':') - return 0; - s++; - t.tm_sec = (s[0] - '0') * 10 + (s[1] - '0'); - s += 2; - if (*s != ' ') - return 0; - s++; - - /* timezone */ - tz = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 + ((s[3] - '0') * 10 + (s[4] - '0')) * 60; - if (s[0] == '+') - tz = -tz; - - return (mutt_mktime(&t, 0) + tz); -} - -/** - * imap_make_date - format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz - * - * Caller should provide a buffer of IMAP_DATELEN bytes - */ -void imap_make_date(char *buf, time_t timestamp) -{ - struct tm *tm = localtime(×tamp); - time_t tz = mutt_local_tz(timestamp); - - tz /= 60; - - snprintf(buf, IMAP_DATELEN, "%02d-%s-%d %02d:%02d:%02d %+03d%02d", - tm->tm_mday, Months[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, - tm->tm_min, tm->tm_sec, (int) tz / 60, (int) abs((int) tz) % 60); -} - /** * imap_qualify_path - Make an absolute IMAP folder target * @@ -862,30 +795,6 @@ void imap_unmunge_mbox_name(struct ImapData *idata, char *s) FREE(&buf); } -/** - * imap_wordcasecmp - find word a in word list b - */ -int imap_wordcasecmp(const char *a, const char *b) -{ - char tmp[SHORT_STRING]; - char *s = (char *) b; - int i; - - tmp[SHORT_STRING - 1] = '\0'; - for (i = 0; i < SHORT_STRING - 2; i++, s++) - { - if (!*s || ISSPACE(*s)) - { - tmp[i] = '\0'; - break; - } - tmp[i] = *s; - } - tmp[i + 1] = '\0'; - - return mutt_strcasecmp(a, tmp); -} - /* * Imap keepalive: poll the current folder to keep the * connection alive. diff --git a/init.c b/init.c index 126971abf..d2496e845 100644 --- a/init.c +++ b/init.c @@ -3713,32 +3713,6 @@ done: return 0; } -/** - * rstrnstr - Find last instance of a substring - * - * Return the last instance of needle in the haystack, or NULL. - * Like strstr(), only backwards, and for a limited haystack length. - */ -static const char *rstrnstr(const char *haystack, size_t haystack_length, const char *needle) -{ - int needle_length = strlen(needle); - const char *haystack_end = haystack + haystack_length - needle_length; - const char *p = NULL; - - for (p = haystack_end; p >= haystack; --p) - { - for (size_t i = 0; i < needle_length; ++i) - { - if (p[i] != needle[i]) - goto next; - } - return p; - - next:; - } - return NULL; -} - /** * mutt_nm_query_complete - Complete to the nearest notmuch tag * diff --git a/lib/date.c b/lib/date.c index 7a960814e..a668d4a99 100644 --- a/lib/date.c +++ b/lib/date.c @@ -33,6 +33,8 @@ * * | Function | Description * | :-------------------- | :-------------------------------------------------- + * | imap_make_date() | Format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz + * | imap_parse_date() | Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz * | is_day_name() | Is the string a valid day name * | mutt_check_month() | Is the string a valid month name * | mutt_local_tz() | Calculate the local timezone in seconds east of UTC @@ -590,3 +592,78 @@ time_t mutt_parse_date(const char *s, struct Tz *tz_out) return (mutt_mktime(&tm, 0) + tz_offset); } + +/** + * imap_make_date - Format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz + * @param buf Buffer to store the results + * @param buflen Length of buffer + * @param timestamp Time to format + * @retval int Number of characters written to buf + * + * Caller should provide a buffer of at least 27 bytes. + */ +int imap_make_date(char *buf, size_t buflen, time_t timestamp) +{ + struct tm *tm = localtime(×tamp); + time_t tz = mutt_local_tz(timestamp); + + tz /= 60; + + return snprintf(buf, buflen, "%02d-%s-%d %02d:%02d:%02d %+03d%02d", + tm->tm_mday, Months[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, + tm->tm_min, tm->tm_sec, (int) tz / 60, (int) abs((int) tz) % 60); +} + +/** + * imap_parse_date - Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz + * @param str Date in string form + * @retval 0 Error + * @retval time_t Unix time + */ +time_t imap_parse_date(char *s) +{ + struct tm t; + time_t tz; + + t.tm_mday = (s[0] == ' ' ? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0')); + s += 2; + if (*s != '-') + return 0; + s++; + t.tm_mon = mutt_check_month(s); + s += 3; + if (*s != '-') + return 0; + s++; + t.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + + (s[3] - '0') - 1900; + s += 4; + if (*s != ' ') + return 0; + s++; + + /* time */ + t.tm_hour = (s[0] - '0') * 10 + (s[1] - '0'); + s += 2; + if (*s != ':') + return 0; + s++; + t.tm_min = (s[0] - '0') * 10 + (s[1] - '0'); + s += 2; + if (*s != ':') + return 0; + s++; + t.tm_sec = (s[0] - '0') * 10 + (s[1] - '0'); + s += 2; + if (*s != ' ') + return 0; + s++; + + /* timezone */ + tz = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 + ((s[3] - '0') * 10 + (s[4] - '0')) * 60; + if (s[0] == '+') + tz = -tz; + + return (mutt_mktime(&t, 0) + tz); +} + diff --git a/lib/date.h b/lib/date.h index fab7a1b8f..9594b98ff 100644 --- a/lib/date.h +++ b/lib/date.h @@ -41,12 +41,14 @@ extern const char *const Weekdays[]; extern const char *const Months[]; extern const struct Tz TimeZones[]; -time_t mutt_local_tz(time_t t); -time_t mutt_mktime(struct tm *t, int local); -void mutt_normalize_time(struct tm *tm); -char *mutt_make_date(char *buf, size_t buflen); -time_t mutt_parse_date(const char *s, struct Tz *tz_out); -bool is_day_name(const char *s); -int mutt_check_month(const char *s); +int imap_make_date(char *buf, size_t buflen, time_t timestamp); +time_t imap_parse_date(char *s); +bool is_day_name(const char *s); +int mutt_check_month(const char *s); +time_t mutt_local_tz(time_t t); +char *mutt_make_date(char *buf, size_t buflen); +time_t mutt_mktime(struct tm *t, int local); +void mutt_normalize_time(struct tm *tm); +time_t mutt_parse_date(const char *s, struct Tz *tz_out); #endif /* _LIB_DATE_H */ diff --git a/lib/string.c b/lib/string.c index 070369062..b1b8ef643 100644 --- a/lib/string.c +++ b/lib/string.c @@ -27,6 +27,7 @@ * * | Function | Description * | :------------------------ | :--------------------------------------------------------- + * | imap_wordcasecmp() | Find word a in word list b * | is_email_wsp() | Is this a whitespace character (for an email header) * | lwslen() | Measure the linear-white-space at the beginning of a string * | lwsrlen() | Measure the linear-white-space at the end of a string @@ -49,6 +50,7 @@ * | mutt_substrcpy() | Copy a sub-string into a buffer * | mutt_substrdup() | Duplicate a sub-string * | rfc822_dequote_comment() | Un-escape characters in an email address comment + * | rstrnstr() | Find last instance of a substring * | safe_strcat() | Concatenate two strings * | safe_strdup() | Copy a string, safely * | safe_strncat() | Concatenate two strings @@ -683,3 +685,67 @@ const char *next_word(const char *s) SKIPWS(s); return s; } + +/** + * rstrnstr - Find last instance of a substring + * @param haystack String to search through + * @param haystack_length Length of the string + * @param needle String to find + * @retval NULL String not found + * @retval ptr Location of string + * + * Return the last instance of needle in the haystack, or NULL. + * Like strstr(), only backwards, and for a limited haystack length. + */ +const char *rstrnstr(const char *haystack, size_t haystack_length, const char *needle) +{ + int needle_length = strlen(needle); + const char *haystack_end = haystack + haystack_length - needle_length; + const char *p = NULL; + + for (p = haystack_end; p >= haystack; --p) + { + for (size_t i = 0; i < needle_length; ++i) + { + if (p[i] != needle[i]) + goto next; + } + return p; + + next:; + } + return NULL; +} + +/** + * imap_wordcasecmp - Find word a in word list b + * @param a Word to find + * @param b String to check + * @retval 0 Word was found + * @retval !=0 Word was not found + * + * Given a word "apple", check if it exists at the start of a string of words, + * e.g. "apple banana". It must be an exact match, so "apple" won't match + * "apples banana". + * + * The case of the words is ignored. + */ +int imap_wordcasecmp(const char *a, const char *b) +{ + char tmp[SHORT_STRING] = ""; + + int i; + for (i = 0; i < SHORT_STRING - 2; i++, b++) + { + if (!*b || ISSPACE(*b)) + { + tmp[i] = '\0'; + break; + } + tmp[i] = *b; + } + tmp[i + 1] = '\0'; + + return mutt_strcasecmp(a, tmp); +} + diff --git a/lib/string2.h b/lib/string2.h index 9fb4e7e72..6b4a6dc76 100644 --- a/lib/string2.h +++ b/lib/string2.h @@ -56,6 +56,7 @@ #define terminate_buffer(a, b) terminate_string(a, b, sizeof(a) - 1) +int imap_wordcasecmp(const char *a, const char *b); int is_email_wsp(char c); size_t lwslen(const char *s, size_t n); size_t lwsrlen(const char *s, size_t n); @@ -79,6 +80,7 @@ char * mutt_substrcpy(char *dest, const char *begin, const char *end, size_ char * mutt_substrdup(const char *begin, const char *end); const char *next_word(const char *s); void rfc822_dequote_comment(char *s); +const char *rstrnstr(const char *haystack, size_t haystack_length, const char *needle); char * safe_strcat(char *d, size_t l, const char *s); char * safe_strdup(const char *s); char * safe_strncat(char *d, size_t l, const char *s, size_t sl); -- 2.40.0