Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>

char    dayw[] =
{
        " S  M Tu  W Th  F  S"
};
char    *smon[] =
{
        "January", "February", "March", "April",
        "May", "June", "July", "August",
        "September", "October", "November", "December",
};
char    mon[] =
{
        0,
        31, 29, 31, 30,
        31, 30, 31, 31,
        30, 31, 30, 31,
};
char    string[432];
Biobuf  bout;

void    main(int argc, char *argv[]);
int     number(char *str);
void    pstr(char *str, int n);
void    cal(int m, int y, char *p, int w);
int     jan1(int yr);
int     curmo(void);
int     curyr(void);

void
main(int argc, char *argv[])
{
        int y, i, j, m;

        if(argc > 3) {
                fprint(2, "usage: cal [month] [year]\n");
                exits("usage");
        }
        Binit(&bout, 1, OWRITE);

/*
 * no arg, print current month
 */
        if(argc == 1) {
                m = curmo();
                y = curyr();
                goto xshort;
        }

/*
 * one arg
 *      if looks like a month, print month
 *      else print year
 */
        if(argc == 2) {
                y = number(argv[1]);
                if(y < 0)
                        y = -y;
                if(y >= 1 && y <= 12) {
                        m = y;
                        y = curyr();
                        goto xshort;
                }
                goto xlong;
        }

/*
 * two arg, month and year
 */
        m = number(argv[1]);
        if(m < 0)
                m = -m;
        y = number(argv[2]);
        goto xshort;

/*
 *      print out just month
 */
xshort:
        if(m < 1 || m > 12)
                goto badarg;
        if(y < 1 || y > 9999)
                goto badarg;
        Bprint(&bout, "   %s %ud\n", smon[m-1], y);
        Bprint(&bout, "%s\n", dayw);
        cal(m, y, string, 24);
        for(i=0; i<6*24; i+=24)
                pstr(string+i, 24);
        exits(0);

/*
 *      print out complete year
 */
xlong:
        y = number(argv[1]);
        if(y<1 || y>9999)
                goto badarg;
        Bprint(&bout, "\n\n\n");
        Bprint(&bout, "                                %ud\n", y);
        Bprint(&bout, "\n");
        for(i=0; i<12; i+=3) {
                for(j=0; j<6*72; j++)
                        string[j] = '\0';
                Bprint(&bout, "         %.3s", smon[i]);
                Bprint(&bout, "                    %.3s", smon[i+1]);
                Bprint(&bout, "                    %.3s\n", smon[i+2]);
                Bprint(&bout, "%s   %s   %s\n", dayw, dayw, dayw);
                cal(i+1, y, string, 72);
                cal(i+2, y, string+23, 72);
                cal(i+3, y, string+46, 72);
                for(j=0; j<6*72; j+=72)
                        pstr(string+j, 72);
        }
        Bprint(&bout, "\n\n\n");
        exits(0);

badarg:
        Bprint(&bout, "cal: bad argument\n");
}

struct
{
        char*   word;
        int     val;
} dict[] =
{
        "jan",          1,
        "january",      1,
        "feb",          2,
        "february",     2,
        "mar",          3,
        "march",        3,
        "apr",          4,
        "april",        4,
        "may",          5,
        "jun",          6,
        "june",         6,
        "jul",          7,
        "july",         7,
        "aug",          8,
        "august",       8,
        "sep",          9,
        "sept",         9,
        "september",    9,
        "oct",          10,
        "october",      10,
        "nov",          11,
        "november",     11,
        "dec",          12,
        "december",     12,
        0
};

/*
 * convert to a number.
 * if its a dictionary word,
 * return negative  number
 */
int
number(char *str)
{
        int n, c;
        char *s;

        for(n=0; s=dict[n].word; n++)
                if(strcmp(s, str) == 0)
                        return -dict[n].val;
        n = 0;
        s = str;
        while(c = *s++) {
                if(c<'0' || c>'9')
                        return 0;
                n = n*10 + c-'0';
        }
        return n;
}

void
pstr(char *str, int n)
{
        int i;
        char *s;

        s = str;
        i = n;
        while(i--)
                if(*s++ == '\0')
                        s[-1] = ' ';
        i = n+1;
        while(i--)
                if(*--s != ' ')
                        break;
        s[1] = '\0';
        Bprint(&bout, "%s\n", str);
}

void
cal(int m, int y, char *p, int w)
{
        int d, i;
        char *s;

        s = p;
        d = jan1(y);
        mon[2] = 29;
        mon[9] = 30;

        switch((jan1(y+1)+7-d)%7) {

        /*
         *      non-leap year
         */
        case 1:
                mon[2] = 28;
                break;

        /*
         *      1752
         */
        default:
                mon[9] = 19;
                break;

        /*
         *      leap year
         */
        case 2:
                ;
        }
        for(i=1; i<m; i++)
                d += mon[i];
        d %= 7;
        s += 3*d;
        for(i=1; i<=mon[m]; i++) {
                if(i==3 && mon[m]==19) {
                        i += 11;
                        mon[m] += 11;
                }
                if(i > 9)
                        *s = i/10+'0';
                s++;
                *s++ = i%10+'0';
                s++;
                if(++d == 7) {
                        d = 0;
                        s = p+w;
                        p = s;
                }
        }
}

/*
 *      return day of the week
 *      of jan 1 of given year
 */
int
jan1(int yr)
{
        int y, d;

/*
 *      normal gregorian calendar
 *      one extra day per four years
 */

        y = yr;
        d = 4+y+(y+3)/4;

/*
 *      julian calendar
 *      regular gregorian
 *      less three days per 400
 */

        if(y > 1800) {
                d -= (y-1701)/100;
                d += (y-1601)/400;
        }

/*
 *      great calendar changeover instant
 */

        if(y > 1752)
                d += 3;

        return d%7;
}

/*
 * system dependent
 * get current month and year
 */
int
curmo(void)
{
        Tm *tm;

        tm = localtime(time(0));
        return tm->mon+1;
}

int
curyr(void)
{
        Tm *tm;

        tm = localtime(time(0));
        return tm->year+1900;
}