This is my first post on this forum. I have read the guidelines and will try to adhere to them, but I apologize if I miss something. The code I am posting is intended to duplicate the output of "date -u" in the XV6 OS. It does this, with the exception of dates before the 1700s (This wasn't relevant to the task, and the math is a little different, from what I read). My goal with this post is to seek advice on improving the code in terms of safety and performance, with an emphasis on best practices that I can generalize to future C code (I realize this may not be as doable for something intended to run in XV6). Advice on both my code and better techniques for posting here is appreciated!
#include "types.h"
#include "stat.h"
#include "user.h"
#include "date.h"
int check_leap(int year);
void print_day(int year, int month, int day);
void print_month(int month);
int month_key(int month);
int
main(void)
{
struct rtcdate current_date;
if(date(¤t_date) != 0)
exit();
print_day(current_date.year, current_date.month, current_date.day);
print_month(current_date.month);
printf(1, " %d",current_date.day);
printf(1," %d:%d:%d", current_date.hour, current_date.minute, current_date.second);
printf(1," %d", current_date.year);
printf(1," UTC\n");
exit();
}
int
check_leap(int year)
{
if(year % 4 == 0)
{
if(year % 100 == 0)
{
if(year % 400 == 0)
return 1; //Leap year
}
}
return 0;
}
int
month_key(int month)
{
int key;
switch (month)
{
case 1: key = 1;
break;
case 2: key = 4;
break;
case 3: key = 4;
break;
case 4: key = 0;
break;
case 5: key = 2;
break;
case 6: key = 5;
break;
case 7: key = 0;
break;
case 8: key = 3;
break;
case 9: key = 6;
break;
case 10: key = 1;
break;
case 11: key = 4;
break;
case 12: key = 6;
break;
default: key = -1;
break;
}
return key;
}
void
print_day(int year, int month, int day)
{
int week_day;
int decade = year % 100;
int century = year / 100;
int leap = check_leap(year);
int key = month_key(month);
if(key < 0)
{
printf(1, "%s", "Invalid value for month!\n");
exit();
}
week_day = decade / 4;
week_day += day;
week_day += key;
if((leap) && ((month == 1) || (month == 2)))
{
week_day -= 1;
}
switch (century)
{
case 17: week_day += 4;
break;
case 18: week_day += 2;
break;
case 19: break;
case 20: week_day += 6;
break;
default: printf(1, "%s", "Centuries before 1700 or after 2000 not yet supported. \n");
break;
}
week_day += decade;
week_day = (week_day % 7) - 1;
if(week_day < 0 || week_day > 6)
{
printf(1, "Invalid Day error!"); //TS code- to be removed
}
switch(week_day)
{
case 0: printf(1, "Sun ");
break;
case 1: printf(1, "Mon ");
break;
case 2: printf(1, "Tue ");
break;
case 3: printf(1, "Wed ");
break;
case 4: printf(1, "Thu ");
break;
case 5: printf(1, "Fri ");
break;
case 6: printf(1, "Sat ");
break;
default: printf(1, "Unknown day!");
break;
}
return;
}
void
print_month(int month)
{
switch (month)
{
case 1: printf(1, "Jan");
break;
case 2: printf(1, "Feb");
break;
case 3: printf(1, "Mar");
break;
case 4: printf(1, "Apr");
break;
case 5: printf(1, "May");
break;
case 6: printf(1, "Jun");
break;
case 7: printf(1, "Jul");
break;
case 8: printf(1, "Aug");
break;
case 9: printf(1, "Sep");
break;
case 10: printf(1, "Oct");
break;
case 11: printf(1, "Nov");
break;
case 12: printf(1, "Dec");
break;
default: printf(1, "Month Error");
break;
}
return;
}
1 Answer 1
XV6 bizarreness
XV6 has made at least one ill-advised decision in forcing a non-standard signature of printf
that requires a file descriptor be passed in. Maybe they should have omitted printf
entirely and made you use fprintf
instead, but anyway: at the least, you should make a stdout
constant equal to 1 and use this instead of the numeric literal.
You could actually make #define
shims in a header file that centralize the XV6-to-C99 translation, including a definition for fprintf
that you can call as you would the standard version, but in fact calls the XV6 printf
internally. If you're in a course that forces non-standard C but you still want to learn standard C this would be a sane option.
Also, does returning from main
not work? If it does, return
instead of exit()
.
month_key
Re-express this long, continuous switch
as a static const
lookup array that you index into, after having performed a bounds check. The same is possible for your switch (week_day)
and switch (month)
.
Explore related questions
See similar questions with these tags.
check_leap()
. The change from Juliann to Gregorian calendar and it leap year rules only begin in 1582. The new rule were only accepted by the majority of the planet in the 19xx, well past 1700s. The old rules continue is use today in select venues. \$\endgroup\$