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