vary.c revision 27874
127874Sbrian#include <time.h> 227874Sbrian#include <string.h> 327874Sbrian#include <stdlib.h> 427874Sbrian#include "vary.h" 527874Sbrian 627874Sbrianstruct trans { 727874Sbrian int val; 827874Sbrian char *str; 927874Sbrian}; 1027874Sbrian 1127874Sbrianstatic struct trans trans_mon[] = { 1227874Sbrian { 1, "jan" }, { 2, "feb" }, { 3, "mar" }, { 4, "apr" }, { 5, "may" }, 1327874Sbrian { 6, "jun" }, { 7, "jul" }, { 8, "aug" }, { 9, "sep" }, { 10, "oct" }, 1427874Sbrian { 11, "nov" }, { 12, "dec" }, 1527874Sbrian { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" }, 1627874Sbrian { 6, "june" }, { 7, "july" }, { 8, "august" }, { 9, "september" }, 1727874Sbrian { 10, "october" }, { 11, "november" }, { 12, "december" }, 1827874Sbrian { -1, NULL } 1927874Sbrian}; 2027874Sbrian 2127874Sbrianstatic struct trans trans_wday[] = { 2227874Sbrian { 0, "sun" }, { 1, "mon" }, { 2, "tue" }, { 3, "wed" }, { 4, "thr" }, 2327874Sbrian { 4, "thu" }, { 5, "fri" }, { 6, "sat" }, 2427874Sbrian { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" }, 2527874Sbrian { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" }, 2627874Sbrian { -1, NULL } 2727874Sbrian}; 2827874Sbrian 2927874Sbrianstatic char digits[] = "0123456789"; 3027874Sbrian 3127874Sbrianstatic int 3227874Sbriantrans(const struct trans t[], const char *arg) 3327874Sbrian{ 3427874Sbrian int f; 3527874Sbrian 3627874Sbrian if (strspn(arg, digits) == strlen(arg)) 3727874Sbrian return atoi(arg); 3827874Sbrian 3927874Sbrian for (f = 0; t[f].val != -1; f++) 4027874Sbrian if (!strcasecmp(t[f].str, arg)) 4127874Sbrian return t[f].val; 4227874Sbrian 4327874Sbrian return -1; 4427874Sbrian} 4527874Sbrian 4627874Sbrianstruct vary * 4727874Sbrianvary_append(struct vary *v, char flag, char *arg) 4827874Sbrian{ 4927874Sbrian struct vary *result, **nextp; 5027874Sbrian 5127874Sbrian if (!strchr("DWMY", flag)) 5227874Sbrian return 0; 5327874Sbrian 5427874Sbrian if (v) { 5527874Sbrian result = v; 5627874Sbrian while (v->next) 5727874Sbrian v = v->next; 5827874Sbrian nextp = &v->next; 5927874Sbrian } else 6027874Sbrian nextp = &result; 6127874Sbrian 6227874Sbrian *nextp = (struct vary *)malloc(sizeof(struct vary)); 6327874Sbrian (*nextp)->flag = flag; 6427874Sbrian (*nextp)->arg = arg; 6527874Sbrian (*nextp)->next = NULL; 6627874Sbrian return result; 6727874Sbrian} 6827874Sbrian 6927874Sbrianstatic int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 7027874Sbrian 7127874Sbrianstatic int 7227874Sbriandaysinmonth(const struct tm *t) 7327874Sbrian{ 7427874Sbrian int year; 7527874Sbrian 7627874Sbrian year = t->tm_year + 1900; 7727874Sbrian 7827874Sbrian if (t->tm_mon == 1) 7927874Sbrian if (!(year % 400)) 8027874Sbrian return 29; 8127874Sbrian else if (!(year % 100)) 8227874Sbrian return 28; 8327874Sbrian else if (!(year % 4)) 8427874Sbrian return 29; 8527874Sbrian else 8627874Sbrian return 28; 8727874Sbrian else if (t->tm_mon >= 0 && t->tm_mon < 12) 8827874Sbrian return mdays[t->tm_mon]; 8927874Sbrian 9027874Sbrian return 0; 9127874Sbrian} 9227874Sbrian 9327874Sbrian 9427874Sbrianstatic int 9527874Sbrianadjyear(struct tm *t, char type, int val) 9627874Sbrian{ 9727874Sbrian switch (type) { 9827874Sbrian case '+': 9927874Sbrian t->tm_year += val; 10027874Sbrian break; 10127874Sbrian case '-': 10227874Sbrian t->tm_year -= val; 10327874Sbrian break; 10427874Sbrian default: 10527874Sbrian t->tm_year = val; 10627874Sbrian if (t->tm_year < 69) 10727874Sbrian t->tm_year += 100; /* as per date.c */ 10827874Sbrian else if (t->tm_year > 1900) 10927874Sbrian t->tm_year -= 1900; /* struct tm holds years since 1900 */ 11027874Sbrian break; 11127874Sbrian } 11227874Sbrian return mktime(t) != -1; 11327874Sbrian} 11427874Sbrian 11527874Sbrianstatic int 11627874Sbriansadjyear(struct tm *t, char *arg) 11727874Sbrian{ 11827874Sbrian switch (*arg) { 11927874Sbrian case '+': 12027874Sbrian case '-': 12127874Sbrian return adjyear(t, *arg, atoi(arg+1)); 12227874Sbrian default: 12327874Sbrian return adjyear(t, '\0', atoi(arg)); 12427874Sbrian } 12527874Sbrian} 12627874Sbrian 12727874Sbrianstatic int 12827874Sbrianadjmon(struct tm *t, char type, int val, int istext) 12927874Sbrian{ 13027874Sbrian if (val < 0) 13127874Sbrian return 0; 13227874Sbrian 13327874Sbrian switch (type) { 13427874Sbrian case '+': 13527874Sbrian if (istext) 13627874Sbrian if (val <= t->tm_mon) 13727874Sbrian val += 11 - t->tm_mon; /* early next year */ 13827874Sbrian else 13927874Sbrian val -= t->tm_mon + 1; /* later this year */ 14027874Sbrian if (!adjyear(t, '+', (t->tm_mon + val) / 12)) 14127874Sbrian return 0; 14227874Sbrian val %= 12; 14327874Sbrian t->tm_mon += val; 14427874Sbrian if (t->tm_mon > 11) 14527874Sbrian t->tm_mon -= 12; 14627874Sbrian break; 14727874Sbrian 14827874Sbrian case '-': 14927874Sbrian if (istext) 15027874Sbrian if (val-1 > t->tm_mon) 15127874Sbrian val = 13 - val + t->tm_mon; /* later last year */ 15227874Sbrian else 15327874Sbrian val = t->tm_mon - val + 1; /* early this year */ 15427874Sbrian if (!adjyear(t, '-', val / 12)) 15527874Sbrian return 0; 15627874Sbrian val %= 12; 15727874Sbrian if (val > t->tm_mon) { 15827874Sbrian if (!adjyear(t, '-', 1)) 15927874Sbrian return 0; 16027874Sbrian val -= 12; 16127874Sbrian } 16227874Sbrian t->tm_mon -= val; 16327874Sbrian break; 16427874Sbrian 16527874Sbrian default: 16627874Sbrian if (val > 12 || val < 1) 16727874Sbrian return 0; 16827874Sbrian t->tm_mon = --val; 16927874Sbrian } 17027874Sbrian 17127874Sbrian return mktime(t) != -1; 17227874Sbrian} 17327874Sbrian 17427874Sbrianstatic int 17527874Sbriansadjmon(struct tm *t, char *arg) 17627874Sbrian{ 17727874Sbrian int istext; 17827874Sbrian int val; 17927874Sbrian 18027874Sbrian switch (*arg) { 18127874Sbrian case '+': 18227874Sbrian case '-': 18327874Sbrian istext = strspn(arg+1, digits) != strlen(arg+1); 18427874Sbrian val = trans(trans_mon, arg+1); 18527874Sbrian return adjmon(t, *arg, val, istext); 18627874Sbrian default: 18727874Sbrian istext = strspn(arg, digits) != strlen(arg); 18827874Sbrian val = trans(trans_mon, arg); 18927874Sbrian return adjmon(t, '\0', val, istext); 19027874Sbrian } 19127874Sbrian} 19227874Sbrian 19327874Sbrianstatic int 19427874Sbrianadjday(struct tm *t, char type, int val) 19527874Sbrian{ 19627874Sbrian int mdays; 19727874Sbrian switch (type) { 19827874Sbrian case '+': 19927874Sbrian while (val) { 20027874Sbrian mdays = daysinmonth(t); 20127874Sbrian if (val > mdays - t->tm_mday) { 20227874Sbrian val -= mdays - t->tm_mday + 1; 20327874Sbrian t->tm_mday = 1; 20427874Sbrian if (!adjmon(t, '+', 1, 0)) 20527874Sbrian return 0; 20627874Sbrian } else { 20727874Sbrian t->tm_mday += val; 20827874Sbrian val = 0; 20927874Sbrian } 21027874Sbrian } 21127874Sbrian break; 21227874Sbrian case '-': 21327874Sbrian while (val) 21427874Sbrian if (val >= t->tm_mday) { 21527874Sbrian val -= t->tm_mday; 21627874Sbrian t->tm_mday = 1; 21727874Sbrian if (!adjmon(t, '-', 1, 0)) 21827874Sbrian return 0; 21927874Sbrian t->tm_mday = daysinmonth(t); 22027874Sbrian } else { 22127874Sbrian t->tm_mday -= val; 22227874Sbrian val = 0; 22327874Sbrian } 22427874Sbrian break; 22527874Sbrian default: 22627874Sbrian if (val > 0 && val <= daysinmonth(t)) 22727874Sbrian t->tm_mday = val; 22827874Sbrian else 22927874Sbrian return 0; 23027874Sbrian break; 23127874Sbrian } 23227874Sbrian 23327874Sbrian return mktime(t) != -1; 23427874Sbrian} 23527874Sbrian 23627874Sbrianstatic int 23727874Sbriansadjwday(struct tm *t, char *arg) 23827874Sbrian{ 23927874Sbrian int istext; 24027874Sbrian int val; 24127874Sbrian 24227874Sbrian switch (*arg) { 24327874Sbrian case '+': 24427874Sbrian case '-': 24527874Sbrian istext = strspn(arg+1, digits) != strlen(arg+1); 24627874Sbrian val = trans(trans_wday, arg+1); 24727874Sbrian break; 24827874Sbrian default: 24927874Sbrian istext = 0; 25027874Sbrian val = trans(trans_wday, arg); 25127874Sbrian break; 25227874Sbrian } 25327874Sbrian 25427874Sbrian if (val < 0) 25527874Sbrian return 0; 25627874Sbrian 25727874Sbrian switch (*arg) { 25827874Sbrian case '+': 25927874Sbrian if (istext) 26027874Sbrian if (val < t->tm_wday) 26127874Sbrian val = 7 - t->tm_wday + val; /* early next week */ 26227874Sbrian else 26327874Sbrian val -= t->tm_wday; /* later this week */ 26427874Sbrian else 26527874Sbrian val *= 7; /* "-W +5" == "5 weeks in the future" */ 26627874Sbrian return adjday(t, '+', val); 26727874Sbrian case '-': 26827874Sbrian if (istext) 26927874Sbrian if (val > t->tm_wday) 27027874Sbrian val = 7 - val + t->tm_wday; /* later last week */ 27127874Sbrian else 27227874Sbrian val = t->tm_wday - val; /* early this week */ 27327874Sbrian else 27427874Sbrian val *= 7; /* "-W -5" == "5 weeks ago" */ 27527874Sbrian return adjday(t, '-', val); 27627874Sbrian default: 27727874Sbrian if (val < t->tm_wday) 27827874Sbrian return adjday(t, '-', t->tm_wday - val); 27927874Sbrian else if (val > 6) 28027874Sbrian return 0; 28127874Sbrian else if (val > t->tm_wday) 28227874Sbrian return adjday(t, '+', val - t->tm_wday); 28327874Sbrian } 28427874Sbrian return 1; 28527874Sbrian} 28627874Sbrian 28727874Sbrianstatic int 28827874Sbriansadjday(struct tm *t, char *arg) 28927874Sbrian{ 29027874Sbrian switch (*arg) { 29127874Sbrian case '+': 29227874Sbrian case '-': 29327874Sbrian return adjday(t, *arg, atoi(arg+1)); 29427874Sbrian default: 29527874Sbrian return adjday(t, '\0', atoi(arg)); 29627874Sbrian } 29727874Sbrian} 29827874Sbrian 29927874Sbrianconst struct vary * 30027874Sbrianvary_apply(const struct vary *v, struct tm *t) 30127874Sbrian{ 30227874Sbrian for (; v; v = v->next) { 30327874Sbrian switch (v->flag) { 30427874Sbrian case 'D': 30527874Sbrian if (!sadjday(t, v->arg)) 30627874Sbrian return v; 30727874Sbrian break; 30827874Sbrian case 'W': 30927874Sbrian if (!sadjwday(t, v->arg)) 31027874Sbrian return v; 31127874Sbrian break; 31227874Sbrian case 'M': 31327874Sbrian if (!sadjmon(t, v->arg)) 31427874Sbrian return v; 31527874Sbrian break; 31627874Sbrian case 'Y': 31727874Sbrian if (!sadjyear(t, v->arg)) 31827874Sbrian return v; 31927874Sbrian break; 32027874Sbrian default: 32127874Sbrian return v; 32227874Sbrian } 32327874Sbrian } 32427874Sbrian return 0; 32527874Sbrian} 32627874Sbrian 32727874Sbrianvoid 32827874Sbrianvary_destroy(struct vary *v) 32927874Sbrian{ 33027874Sbrian struct vary *n; 33127874Sbrian 33227874Sbrian while (v) { 33327874Sbrian n = v->next; 33427874Sbrian free(v); 33527874Sbrian v = n; 33627874Sbrian } 33727874Sbrian} 338