1 /*
2 ***********************************************************************
3 * © 2016 and later: Unicode, Inc. and others.
4 * License & terms of use: http://www.unicode.org/copyright.html
5 ***********************************************************************
6 **********************************************************************
7 * Copyright (C) 1998-2012, International Business Machines Corporation
8 * and others.  All Rights Reserved.
9 **********************************************************************
10 *
11 * File date.c
12 *
13 * Modification History:
14 *
15 *   Date        Name        Description
16 *   06/16/99    stephen     Creation.
17 *******************************************************************************
18 */
19 
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 
24 #include "unicode/uloc.h"
25 #include "unicode/udat.h"
26 #include "unicode/ucal.h"
27 #include "unicode/ustring.h"
28 #include "unicode/uclean.h"
29 
30 #include "uprint.h"
31 
32 #if UCONFIG_NO_FORMATTING
33 
main(int argc,char ** argv)34 int main(int argc, char **argv)
35 {
36   printf("%s: Sorry, UCONFIG_NO_FORMATTING was turned on (see uconfig.h). No formatting can be done. \n", argv[0]);
37   return 0;
38 }
39 #else
40 
41 
42 /* Protos */
43 static void usage(void);
44 
45 static void version(void);
46 
47 static void cal(int32_t month, int32_t year,
48                 UBool useLongNames, UErrorCode *status);
49 
50 static void get_symbols(const UDateFormat *fmt,
51                         UDateFormatSymbolType type,
52                         UChar *array[],
53                         int32_t arrayLength,
54                         int32_t lowestIndex,
55                         int32_t firstIndex,
56                         UErrorCode *status);
57 
58 static void free_symbols(UChar *array[],
59                          int32_t arrayLength);
60 
61 static void get_days(const UDateFormat *fmt,
62                      UChar *days [], UBool useLongNames,
63                      int32_t fdow, UErrorCode *status);
64 
65 static void free_days(UChar *days[]);
66 
67 static void get_months(const UDateFormat *fmt,
68                        UChar *months [], UBool useLongNames,
69                        UErrorCode *status);
70 
71 static void free_months(UChar *months[]);
72 
73 static void indent(int32_t count, FILE *f);
74 
75 static void print_days(UChar *days [], FILE *f, UErrorCode *status);
76 
77 static void  print_month(UCalendar *c,
78                          UChar *days [],
79                          UBool useLongNames, int32_t fdow,
80                          UErrorCode *status);
81 
82 static void  print_year(UCalendar *c,
83                         UChar *days [], UChar *months [],
84                         UBool useLongNames, int32_t fdow,
85                         UErrorCode *status);
86 
87 /* The version of cal */
88 #define CAL_VERSION "1.0"
89 
90 /* Number of days in a week */
91 #define DAY_COUNT 7
92 
93 /* Number of months in a year (yes, 13) */
94 #define MONTH_COUNT 13
95 
96 /* Separation between months in year view */
97 #define MARGIN_WIDTH 4
98 
99 /* Size of stack buffers */
100 #define BUF_SIZE 64
101 
102 /* Patterm string - "MMM yyyy" */
103 static const UChar sShortPat [] = { 0x004D, 0x004D, 0x004D, 0x0020,
104 0x0079, 0x0079, 0x0079, 0x0079 };
105 /* Pattern string - "MMMM yyyy" */
106 static const UChar sLongPat [] = { 0x004D, 0x004D, 0x004D, 0x004D, 0x0020,
107 0x0079, 0x0079, 0x0079, 0x0079 };
108 
109 
110 int
main(int argc,char ** argv)111 main(int argc,
112      char **argv)
113 {
114     int printUsage = 0;
115     int printVersion = 0;
116     UBool useLongNames = 0;
117     int optInd = 1;
118     char *arg;
119     int32_t month = -1, year = -1;
120     UErrorCode status = U_ZERO_ERROR;
121 
122 
123     /* parse the options */
124     for(optInd = 1; optInd < argc; ++optInd) {
125         arg = argv[optInd];
126 
127         /* version info */
128         if(strcmp(arg, "-v") == 0 || strcmp(arg, "--version") == 0) {
129             printVersion = 1;
130         }
131         /* usage info */
132         else if(strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
133             printUsage = 1;
134         }
135         /* use long day names */
136         else if(strcmp(arg, "-l") == 0 || strcmp(arg, "--long") == 0) {
137             useLongNames = 1;
138         }
139         /* POSIX.1 says all arguments after -- are not options */
140         else if(strcmp(arg, "--") == 0) {
141             /* skip the -- */
142             ++optInd;
143             break;
144         }
145         /* unrecognized option */
146         else if(strncmp(arg, "-", strlen("-")) == 0) {
147             printf("cal: invalid option -- %s\n", arg+1);
148             printUsage = 1;
149         }
150         /* done with options, display cal */
151         else {
152             break;
153         }
154     }
155 
156     /* Get the month and year to display, if specified */
157     if(optInd != argc) {
158 
159         /* Month and year specified */
160         if(argc - optInd == 2) {
161             sscanf(argv[optInd], "%d", (int*)&month);
162             sscanf(argv[optInd + 1], "%d", (int*)&year);
163 
164             /* Make sure the month value is legal */
165             if(month < 0 || month > 12) {
166                 printf("icucal: Bad value for month -- %d\n", (int)month);
167 
168                 /* Display usage */
169                 printUsage = 1;
170             }
171 
172             /* Adjust because months are 0-based */
173             --month;
174         }
175         /* Only year specified */
176         else {
177             sscanf(argv[optInd], "%d", (int*)&year);
178         }
179     }
180 
181     /* print usage info */
182     if(printUsage) {
183         usage();
184         return 0;
185     }
186 
187     /* print version info */
188     if(printVersion) {
189         version();
190         return 0;
191     }
192 
193     /* print the cal */
194     cal(month, year, useLongNames, &status);
195 
196     /* ICU cleanup.  Deallocate any memory ICU may be holding.  */
197     u_cleanup();
198 
199     return (U_FAILURE(status) ? 1 : 0);
200 }
201 
202 /* Usage information */
203 static void
usage()204 usage()
205 {
206     puts("Usage: icucal [OPTIONS] [[MONTH] YEAR]");
207     puts("");
208     puts("Options:");
209     puts("  -h, --help        Print this message and exit.");
210     puts("  -v, --version     Print the version number of cal and exit.");
211     puts("  -l, --long        Use long names.");
212     puts("");
213     puts("Arguments (optional):");
214     puts("  MONTH             An integer (1-12) indicating the month to display");
215     puts("  YEAR              An integer indicating the year to display");
216     puts("");
217     puts("For an interesting calendar, look at October 1582");
218 }
219 
220 /* Version information */
221 static void
version()222 version()
223 {
224     printf("icucal version %s (ICU version %s), created by Stephen F. Booth.\n",
225         CAL_VERSION, U_ICU_VERSION);
226     puts(U_COPYRIGHT_STRING);
227 }
228 
229 static void
cal(int32_t month,int32_t year,UBool useLongNames,UErrorCode * status)230 cal(int32_t month,
231     int32_t year,
232     UBool useLongNames,
233     UErrorCode *status)
234 {
235     UCalendar *c;
236     UChar *days [DAY_COUNT];
237     UChar *months [MONTH_COUNT];
238     int32_t fdow;
239 
240     if(U_FAILURE(*status)) return;
241 
242     /* Create a new calendar */
243     c = ucal_open(0, -1, uloc_getDefault(), UCAL_TRADITIONAL, status);
244 
245     /* Determine if we are printing a calendar for one month or for a year */
246 
247     /* Print an entire year */
248     if(month == -1 && year != -1) {
249 
250         /* Set the year */
251         ucal_set(c, UCAL_YEAR, year);
252 
253         /* Determine the first day of the week */
254         fdow = ucal_getAttribute(c, UCAL_FIRST_DAY_OF_WEEK);
255 
256         /* Print the calendar for the year */
257         print_year(c, days, months, useLongNames, fdow, status);
258     }
259 
260     /* Print only one month */
261     else {
262 
263         /* Set the month and the year, if specified */
264         if(month != -1)
265             ucal_set(c, UCAL_MONTH, month);
266         if(year != -1)
267             ucal_set(c, UCAL_YEAR, year);
268 
269         /* Determine the first day of the week */
270         fdow = ucal_getAttribute(c, UCAL_FIRST_DAY_OF_WEEK);
271 
272         /* Print the calendar for the month */
273         print_month(c, days, useLongNames, fdow, status);
274     }
275 
276     /* Clean up */
277     ucal_close(c);
278 }
279 /*
280  * Get a set of DateFormat symbols of a given type.
281  *
282  * lowestIndex is the index of the first symbol to fetch.
283  * (e.g. it will be one to fetch day names, since Sunday is
284  *  day 1 *not* day 0.)
285  *
286  * firstIndex is the index of the symbol to place first in
287  * the output array. This is used when fetching day names
288  * in locales where the week doesn't start on Sunday.
289  */
get_symbols(const UDateFormat * fmt,UDateFormatSymbolType type,UChar * array[],int32_t arrayLength,int32_t lowestIndex,int32_t firstIndex,UErrorCode * status)290 static void get_symbols(const UDateFormat *fmt,
291                         UDateFormatSymbolType type,
292                         UChar *array[],
293                         int32_t arrayLength,
294                         int32_t lowestIndex,
295                         int32_t firstIndex,
296                         UErrorCode *status)
297 {
298     int32_t count, i;
299 
300     if (U_FAILURE(*status)) {
301         return;
302     }
303 
304     count = udat_countSymbols(fmt, type);
305 
306     if(count != arrayLength + lowestIndex) {
307         return;
308     }
309 
310     for(i = 0; i < arrayLength; i++) {
311         int32_t idx = (i + firstIndex) % arrayLength;
312         int32_t size = 1 + udat_getSymbols(fmt, type, idx + lowestIndex, NULL, 0, status);
313 
314         array[idx] = (UChar *) malloc(sizeof(UChar) * size);
315 
316         *status = U_ZERO_ERROR;
317         udat_getSymbols(fmt, type, idx + lowestIndex, array[idx], size, status);
318     }
319 }
320 
321 /* Free the symbols allocated by get_symbols(). */
free_symbols(UChar * array[],int32_t arrayLength)322 static void free_symbols(UChar *array[],
323                          int32_t arrayLength)
324 {
325     int32_t i;
326 
327     for(i = 0; i < arrayLength; i++) {
328         free(array[i]);
329     }
330 }
331 
332 /* Get the day names for the specified locale, in either long or short
333 form.  Also, reorder the days so that they are in the proper order
334 for the locale (not all locales begin weeks on Sunday; in France,
335 weeks start on Monday) */
336 static void
get_days(const UDateFormat * fmt,UChar * days[],UBool useLongNames,int32_t fdow,UErrorCode * status)337 get_days(const UDateFormat *fmt,
338          UChar *days [],
339          UBool useLongNames,
340          int32_t fdow,
341          UErrorCode *status)
342 {
343     UDateFormatSymbolType dayType = (useLongNames ? UDAT_WEEKDAYS : UDAT_SHORT_WEEKDAYS);
344 
345     if(U_FAILURE(*status))
346         return;
347 
348     /* fdow is 1-based */
349     --fdow;
350 
351     get_symbols(fmt, dayType, days, DAY_COUNT, 1, fdow, status);
352 }
353 
free_days(UChar * days[])354 static void free_days(UChar *days[])
355 {
356     free_symbols(days, DAY_COUNT);
357 }
358 
359 /* Get the month names for the specified locale, in either long or
360 short form. */
361 static void
get_months(const UDateFormat * fmt,UChar * months[],UBool useLongNames,UErrorCode * status)362 get_months(const UDateFormat *fmt,
363            UChar *months [],
364            UBool useLongNames,
365            UErrorCode *status)
366 {
367     UDateFormatSymbolType monthType = (useLongNames ? UDAT_MONTHS : UDAT_SHORT_MONTHS);
368 
369     if(U_FAILURE(*status))
370         return;
371 
372     get_symbols(fmt, monthType, months, MONTH_COUNT - 1, 0, 0, status); /* some locales have 13 months, no idea why */
373 }
374 
free_months(UChar * months[])375 static void free_months(UChar *months[])
376 {
377     free_symbols(months, MONTH_COUNT - 1);
378 }
379 
380 /* Indent a certain number of spaces */
381 static void
indent(int32_t count,FILE * f)382 indent(int32_t count,
383        FILE *f)
384 {
385     char c [BUF_SIZE];
386 
387     if(count <= 0)
388     {
389         return;
390     }
391 
392     if(count < BUF_SIZE) {
393         memset(c, (int)' ', count);
394         fwrite(c, sizeof(char), count, f);
395     }
396     else {
397         int32_t i;
398         for(i = 0; i < count; ++i)
399             putc(' ', f);
400     }
401 }
402 
403 /* Print the days */
404 static void
print_days(UChar * days[],FILE * f,UErrorCode * status)405 print_days(UChar *days [],
406            FILE *f,
407            UErrorCode *status)
408 {
409     int32_t i;
410 
411     if(U_FAILURE(*status)) return;
412 
413     /* Print the day names */
414     for(i = 0; i < DAY_COUNT; ++i) {
415         uprint(days[i], f, status);
416         putc(' ', f);
417     }
418 }
419 
420 /* Print out a calendar for c's current month */
421 static void
print_month(UCalendar * c,UChar * days[],UBool useLongNames,int32_t fdow,UErrorCode * status)422 print_month(UCalendar *c,
423             UChar *days [],
424             UBool useLongNames,
425             int32_t fdow,
426             UErrorCode *status)
427 {
428     int32_t width, pad, i, day;
429     int32_t lens [DAY_COUNT];
430     int32_t firstday, current;
431     UNumberFormat *nfmt;
432     UDateFormat *dfmt;
433     UChar s [BUF_SIZE];
434     const UChar *pat = (useLongNames ? sLongPat : sShortPat);
435     int32_t len = (useLongNames ? 9 : 8);
436 
437     if(U_FAILURE(*status)) return;
438 
439 
440     /* ========== Generate the header containing the month and year */
441 
442     /* Open a formatter with a month and year only pattern */
443     dfmt = udat_open(UDAT_PATTERN,UDAT_PATTERN,NULL,NULL,0,pat, len,status);
444 
445     /* Format the date */
446     udat_format(dfmt, ucal_getMillis(c, status), s, BUF_SIZE, 0, status);
447 
448 
449     /* ========== Get the day names */
450     get_days(dfmt, days, useLongNames, fdow, status);
451 
452     /* ========== Print the header */
453 
454     /* Calculate widths for justification */
455     width = 6; /* 6 spaces, 1 between each day name */
456     for(i = 0; i < DAY_COUNT; ++i) {
457         lens[i] = u_strlen(days[i]);
458         width += lens[i];
459     }
460 
461     /* Print the header, centered among the day names */
462     pad = width - u_strlen(s);
463     indent(pad / 2, stdout);
464     uprint(s, stdout, status);
465     putc('\n', stdout);
466 
467 
468     /* ========== Print the day names */
469 
470     print_days(days, stdout, status);
471     putc('\n', stdout);
472 
473 
474     /* ========== Print the calendar */
475 
476     /* Get the first of the month */
477     ucal_set(c, UCAL_DATE, 1);
478     firstday = ucal_get(c, UCAL_DAY_OF_WEEK, status);
479 
480     /* The day of the week for the first day of the month is based on
481     1-based days of the week, which were also reordered when placed
482     in the days array.  Account for this here by offsetting by the
483     first day of the week for the locale, which is also 1-based. */
484     firstday -= fdow;
485 
486     /* Open the formatter */
487     nfmt = unum_open(UNUM_DECIMAL, NULL,0,NULL,NULL, status);
488 
489     /* Indent the correct number of spaces for the first week */
490     current = firstday;
491     if(current < 0)
492     {
493        current += 7;
494     }
495     for(i = 0; i < current; ++i)
496         indent(lens[i] + 1, stdout);
497 
498     /* Finally, print out the days */
499     day = ucal_get(c, UCAL_DATE, status);
500     do {
501 
502         /* Format the current day string */
503         unum_format(nfmt, day, s, BUF_SIZE, 0, status);
504 
505         /* Calculate the justification and indent */
506         pad = lens[current] - u_strlen(s);
507         indent(pad, stdout);
508 
509         /* Print the day number out, followed by a space */
510         uprint(s, stdout, status);
511         putc(' ', stdout);
512 
513         /* Update the current day */
514         ++current;
515         current %= DAY_COUNT;
516 
517         /* If we're at day 0 (first day of the week), insert a newline */
518         if(current == 0) {
519             putc('\n', stdout);
520         }
521 
522         /* Go to the next day */
523         ucal_add(c, UCAL_DATE, 1, status);
524         day = ucal_get(c, UCAL_DATE, status);
525 
526     } while(day != 1);
527 
528     /* Output a trailing newline */
529     putc('\n', stdout);
530 
531     /* Clean up */
532     free_days(days);
533     unum_close(nfmt);
534     udat_close(dfmt);
535 }
536 
537 /* Print out a calendar for c's current year */
538 static void
print_year(UCalendar * c,UChar * days[],UChar * months[],UBool useLongNames,int32_t fdow,UErrorCode * status)539 print_year(UCalendar *c,
540            UChar *days [],
541            UChar *months [],
542            UBool useLongNames,
543            int32_t fdow,
544            UErrorCode *status)
545 {
546     int32_t width, pad, i, j;
547     int32_t lens [DAY_COUNT];
548     UNumberFormat *nfmt;
549     UDateFormat *dfmt;
550     UChar s [BUF_SIZE];
551     const UChar pat [] = { 0x0079, 0x0079, 0x0079, 0x0079 };
552     int32_t len = 4;
553     UCalendar  *left_cal, *right_cal;
554     int32_t left_day, right_day;
555     int32_t left_firstday, right_firstday, left_current, right_current;
556     int32_t left_month, right_month;
557 
558     if(U_FAILURE(*status)) return;
559 
560     /* Alias */
561     left_cal = c;
562 
563     /* ========== Generate the header containing the year (only) */
564 
565     /* Open a formatter with a month and year only pattern */
566     dfmt = udat_open(UDAT_PATTERN,UDAT_PATTERN,NULL,NULL,0,pat, len, status);
567 
568     /* Format the date */
569     udat_format(dfmt, ucal_getMillis(left_cal, status), s, BUF_SIZE, 0, status);
570 
571     /* ========== Get the month and day names */
572     get_days(dfmt, days, useLongNames, fdow, status);
573     get_months(dfmt, months, useLongNames, status);
574 
575     /* ========== Print the header, centered */
576 
577     /* Calculate widths for justification */
578     width = 6; /* 6 spaces, 1 between each day name */
579     for(i = 0; i < DAY_COUNT; ++i) {
580         lens[i] = u_strlen(days[i]);
581         width += lens[i];
582     }
583 
584     /* width is the width for 1 calendar; we are displaying in 2 cols
585     with MARGIN_WIDTH spaces between months */
586 
587     /* Print the header, centered among the day names */
588     pad = 2 * width + MARGIN_WIDTH - u_strlen(s);
589     indent(pad / 2, stdout);
590     uprint(s, stdout, status);
591     putc('\n', stdout);
592     putc('\n', stdout);
593 
594     /* Generate a copy of the calendar to use */
595     right_cal = ucal_open(0, -1, uloc_getDefault(), UCAL_TRADITIONAL, status);
596     ucal_setMillis(right_cal, ucal_getMillis(left_cal, status), status);
597 
598     /* Open the formatter */
599     nfmt = unum_open(UNUM_DECIMAL,NULL, 0,NULL,NULL, status);
600 
601     /* ========== Calculate and display the months, two at a time */
602     for(i = 0; i < MONTH_COUNT - 1; i += 2) {
603 
604         /* Print the month names for the two current months */
605         pad = width - u_strlen(months[i]);
606         indent(pad / 2, stdout);
607         uprint(months[i], stdout, status);
608         indent(pad / 2 + MARGIN_WIDTH, stdout);
609         pad = width - u_strlen(months[i + 1]);
610         indent(pad / 2, stdout);
611         uprint(months[i + 1], stdout, status);
612         putc('\n', stdout);
613 
614         /* Print the day names, twice  */
615         print_days(days, stdout, status);
616         indent(MARGIN_WIDTH, stdout);
617         print_days(days, stdout, status);
618         putc('\n', stdout);
619 
620         /* Setup the two calendars */
621         ucal_set(left_cal, UCAL_MONTH, i);
622         ucal_set(left_cal, UCAL_DATE, 1);
623         ucal_set(right_cal, UCAL_MONTH, i + 1);
624         ucal_set(right_cal, UCAL_DATE, 1);
625 
626         left_firstday = ucal_get(left_cal, UCAL_DAY_OF_WEEK, status);
627         right_firstday = ucal_get(right_cal, UCAL_DAY_OF_WEEK, status);
628 
629         /* The day of the week for the first day of the month is based on
630         1-based days of the week.  However, the days were reordered
631         when placed in the days array.  Account for this here by
632         offsetting by the first day of the week for the locale, which
633         is also 1-based. */
634 
635         /* We need to mod by DAY_COUNT since fdow can be > firstday.  IE,
636         if fdow = 2 = Monday (like in France) and the first day of the
637         month is a 1 = Sunday, we want firstday to be 6, not -1 */
638         left_firstday += (DAY_COUNT - fdow);
639         left_firstday %= DAY_COUNT;
640 
641         right_firstday += (DAY_COUNT - fdow);
642         right_firstday %= DAY_COUNT;
643 
644         left_current = left_firstday;
645         right_current = right_firstday;
646 
647         left_day = ucal_get(left_cal, UCAL_DATE, status);
648         right_day = ucal_get(right_cal, UCAL_DATE, status);
649 
650         left_month = ucal_get(left_cal, UCAL_MONTH, status);
651         right_month = ucal_get(right_cal, UCAL_MONTH, status);
652 
653         /* Finally, print out the days */
654         while(left_month == i || right_month == i + 1) {
655 
656         /* If the left month is finished printing, but the right month
657         still has days to be printed, indent the width of the days
658             strings and reset the left calendar's current day to 0 */
659             if(left_month != i && right_month == i + 1) {
660                 indent(width + 1, stdout);
661                 left_current = 0;
662             }
663 
664             while(left_month == i) {
665 
666             /* If the day is the first, indent the correct number of
667                 spaces for the first week */
668                 if(left_day == 1) {
669                     for(j = 0; j < left_current; ++j)
670                         indent(lens[j] + 1, stdout);
671                 }
672 
673                 /* Format the current day string */
674                 unum_format(nfmt, left_day, s, BUF_SIZE, 0, status);
675 
676                 /* Calculate the justification and indent */
677                 pad = lens[left_current] - u_strlen(s);
678                 indent(pad, stdout);
679 
680                 /* Print the day number out, followed by a space */
681                 uprint(s, stdout, status);
682                 putc(' ', stdout);
683 
684                 /* Update the current day */
685                 ++left_current;
686                 left_current %= DAY_COUNT;
687 
688                 /* Go to the next day */
689                 ucal_add(left_cal, UCAL_DATE, 1, status);
690                 left_day = ucal_get(left_cal, UCAL_DATE, status);
691 
692                 /* Determine the month */
693                 left_month = ucal_get(left_cal, UCAL_MONTH, status);
694 
695                 /* If we're at day 0 (first day of the week), break and go to
696                 the next month */
697                 if(left_current == 0) {
698                     break;
699                 }
700             }
701 
702             /* If the current day isn't 0, indent to make up for missing
703             days at the end of the month */
704             if(left_current != 0) {
705                 for(j = left_current; j < DAY_COUNT; ++j)
706                     indent(lens[j] + 1, stdout);
707             }
708 
709             /* Indent between the two months */
710             indent(MARGIN_WIDTH, stdout);
711 
712             while(right_month == i + 1) {
713 
714             /* If the day is the first, indent the correct number of
715                 spaces for the first week */
716                 if(right_day == 1) {
717                     for(j = 0; j < right_current; ++j)
718                         indent(lens[j] + 1, stdout);
719                 }
720 
721                 /* Format the current day string */
722                 unum_format(nfmt, right_day, s, BUF_SIZE, 0, status);
723 
724                 /* Calculate the justification and indent */
725                 pad = lens[right_current] - u_strlen(s);
726                 indent(pad, stdout);
727 
728                 /* Print the day number out, followed by a space */
729                 uprint(s, stdout, status);
730                 putc(' ', stdout);
731 
732                 /* Update the current day */
733                 ++right_current;
734                 right_current %= DAY_COUNT;
735 
736                 /* Go to the next day */
737                 ucal_add(right_cal, UCAL_DATE, 1, status);
738                 right_day = ucal_get(right_cal, UCAL_DATE, status);
739 
740                 /* Determine the month */
741                 right_month = ucal_get(right_cal, UCAL_MONTH, status);
742 
743                 /* If we're at day 0 (first day of the week), break out */
744                 if(right_current == 0) {
745                     break;
746                 }
747 
748             }
749 
750             /* Output a newline */
751             putc('\n', stdout);
752         }
753 
754         /* Output a trailing newline */
755         putc('\n', stdout);
756   }
757 
758   /* Clean up */
759   free_months(months);
760   free_days(days);
761   udat_close(dfmt);
762   unum_close(nfmt);
763   ucal_close(right_cal);
764 }
765 
766 #endif
767