]>
Commit | Line | Data |
---|---|---|
b75a7d8f | 1 | /* |
f3c0d7a5 A |
2 | *********************************************************************** |
3 | * © 2016 and later: Unicode, Inc. and others. | |
4 | * License & terms of use: http://www.unicode.org/copyright.html#License | |
5 | *********************************************************************** | |
b75a7d8f | 6 | ********************************************************************** |
51004dcb | 7 | * Copyright (C) 1998-2012, International Business Machines Corporation |
b75a7d8f A |
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> | |
374ca955 | 22 | #include <stdlib.h> |
b75a7d8f A |
23 | |
24 | #include "unicode/uloc.h" | |
25 | #include "unicode/udat.h" | |
26 | #include "unicode/ucal.h" | |
b75a7d8f A |
27 | #include "unicode/ustring.h" |
28 | #include "unicode/uclean.h" | |
29 | ||
30 | #include "uprint.h" | |
31 | ||
32 | #if UCONFIG_NO_FORMATTING | |
33 | ||
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); | |
374ca955 | 44 | |
b75a7d8f | 45 | static void version(void); |
374ca955 | 46 | |
b75a7d8f A |
47 | static void cal(int32_t month, int32_t year, |
48 | UBool useLongNames, UErrorCode *status); | |
374ca955 A |
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, | |
b75a7d8f | 63 | int32_t fdow, UErrorCode *status); |
374ca955 A |
64 | |
65 | static void free_days(UChar *days[]); | |
66 | ||
67 | static void get_months(const UDateFormat *fmt, | |
68 | UChar *months [], UBool useLongNames, | |
b75a7d8f | 69 | UErrorCode *status); |
374ca955 A |
70 | |
71 | static void free_months(UChar *months[]); | |
72 | ||
b75a7d8f | 73 | static void indent(int32_t count, FILE *f); |
374ca955 A |
74 | |
75 | static void print_days(UChar *days [], FILE *f, UErrorCode *status); | |
76 | ||
b75a7d8f | 77 | static void print_month(UCalendar *c, |
374ca955 | 78 | UChar *days [], |
b75a7d8f A |
79 | UBool useLongNames, int32_t fdow, |
80 | UErrorCode *status); | |
374ca955 | 81 | |
b75a7d8f | 82 | static void print_year(UCalendar *c, |
374ca955 | 83 | UChar *days [], UChar *months [], |
b75a7d8f A |
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 | |
111 | main(int argc, | |
112 | char **argv) | |
113 | { | |
114 | int printUsage = 0; | |
115 | int printVersion = 0; | |
116 | UBool useLongNames = 0; | |
51004dcb | 117 | int optInd = 1; |
b75a7d8f A |
118 | char *arg; |
119 | int32_t month = -1, year = -1; | |
120 | UErrorCode status = U_ZERO_ERROR; | |
121 | ||
122 | ||
123 | /* parse the options */ | |
51004dcb A |
124 | for(optInd = 1; optInd < argc; ++optInd) { |
125 | arg = argv[optInd]; | |
b75a7d8f A |
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 -- */ | |
51004dcb | 142 | ++optInd; |
b75a7d8f A |
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 */ | |
51004dcb | 157 | if(optInd != argc) { |
b75a7d8f A |
158 | |
159 | /* Month and year specified */ | |
51004dcb A |
160 | if(argc - optInd == 2) { |
161 | sscanf(argv[optInd], "%d", (int*)&month); | |
162 | sscanf(argv[optInd + 1], "%d", (int*)&year); | |
b75a7d8f A |
163 | |
164 | /* Make sure the month value is legal */ | |
165 | if(month < 0 || month > 12) { | |
374ca955 | 166 | printf("icucal: Bad value for month -- %d\n", (int)month); |
b75a7d8f A |
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 { | |
51004dcb | 177 | sscanf(argv[optInd], "%d", (int*)&year); |
b75a7d8f A |
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 | |
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 | |
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 | |
230 | cal(int32_t month, | |
231 | int32_t year, | |
232 | UBool useLongNames, | |
233 | UErrorCode *status) | |
234 | { | |
235 | UCalendar *c; | |
374ca955 A |
236 | UChar *days [DAY_COUNT]; |
237 | UChar *months [MONTH_COUNT]; | |
b75a7d8f A |
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 | ||
b75a7d8f A |
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 | ||
b75a7d8f A |
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 | } | |
374ca955 A |
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 | */ | |
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++) { | |
729e4ab9 A |
311 | int32_t idx = (i + firstIndex) % arrayLength; |
312 | int32_t size = 1 + udat_getSymbols(fmt, type, idx + lowestIndex, NULL, 0, status); | |
374ca955 | 313 | |
729e4ab9 | 314 | array[idx] = (UChar *) malloc(sizeof(UChar) * size); |
374ca955 A |
315 | |
316 | *status = U_ZERO_ERROR; | |
729e4ab9 | 317 | udat_getSymbols(fmt, type, idx + lowestIndex, array[idx], size, status); |
374ca955 A |
318 | } |
319 | } | |
320 | ||
321 | /* Free the symbols allocated by get_symbols(). */ | |
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 | } | |
b75a7d8f A |
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 | |
374ca955 A |
337 | get_days(const UDateFormat *fmt, |
338 | UChar *days [], | |
b75a7d8f A |
339 | UBool useLongNames, |
340 | int32_t fdow, | |
341 | UErrorCode *status) | |
342 | { | |
374ca955 | 343 | UDateFormatSymbolType dayType = (useLongNames ? UDAT_WEEKDAYS : UDAT_SHORT_WEEKDAYS); |
b75a7d8f A |
344 | |
345 | if(U_FAILURE(*status)) | |
346 | return; | |
347 | ||
348 | /* fdow is 1-based */ | |
349 | --fdow; | |
374ca955 A |
350 | |
351 | get_symbols(fmt, dayType, days, DAY_COUNT, 1, fdow, status); | |
352 | } | |
353 | ||
354 | static void free_days(UChar *days[]) | |
355 | { | |
356 | free_symbols(days, DAY_COUNT); | |
b75a7d8f A |
357 | } |
358 | ||
359 | /* Get the month names for the specified locale, in either long or | |
360 | short form. */ | |
361 | static void | |
374ca955 A |
362 | get_months(const UDateFormat *fmt, |
363 | UChar *months [], | |
b75a7d8f A |
364 | UBool useLongNames, |
365 | UErrorCode *status) | |
366 | { | |
374ca955 | 367 | UDateFormatSymbolType monthType = (useLongNames ? UDAT_MONTHS : UDAT_SHORT_MONTHS); |
b75a7d8f A |
368 | |
369 | if(U_FAILURE(*status)) | |
370 | return; | |
371 | ||
374ca955 A |
372 | get_symbols(fmt, monthType, months, MONTH_COUNT - 1, 0, 0, status); /* some locales have 13 months, no idea why */ |
373 | } | |
374 | ||
375 | static void free_months(UChar *months[]) | |
376 | { | |
377 | free_symbols(months, MONTH_COUNT - 1); | |
b75a7d8f A |
378 | } |
379 | ||
380 | /* Indent a certain number of spaces */ | |
381 | static void | |
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 | |
374ca955 | 405 | print_days(UChar *days [], |
b75a7d8f A |
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 | |
422 | print_month(UCalendar *c, | |
374ca955 | 423 | UChar *days [], |
b75a7d8f A |
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 */ | |
51004dcb | 443 | dfmt = udat_open(UDAT_PATTERN,UDAT_PATTERN,NULL,NULL,0,pat, len,status); |
b75a7d8f A |
444 | |
445 | /* Format the date */ | |
446 | udat_format(dfmt, ucal_getMillis(c, status), s, BUF_SIZE, 0, status); | |
447 | ||
448 | ||
374ca955 A |
449 | /* ========== Get the day names */ |
450 | get_days(dfmt, days, useLongNames, fdow, status); | |
451 | ||
b75a7d8f A |
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 */ | |
374ca955 | 532 | free_days(days); |
b75a7d8f A |
533 | unum_close(nfmt); |
534 | udat_close(dfmt); | |
535 | } | |
536 | ||
537 | /* Print out a calendar for c's current year */ | |
538 | static void | |
539 | print_year(UCalendar *c, | |
374ca955 A |
540 | UChar *days [], |
541 | UChar *months [], | |
b75a7d8f A |
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 */ | |
51004dcb | 566 | dfmt = udat_open(UDAT_PATTERN,UDAT_PATTERN,NULL,NULL,0,pat, len, status); |
b75a7d8f A |
567 | |
568 | /* Format the date */ | |
569 | udat_format(dfmt, ucal_getMillis(left_cal, status), s, BUF_SIZE, 0, status); | |
570 | ||
374ca955 A |
571 | /* ========== Get the month and day names */ |
572 | get_days(dfmt, days, useLongNames, fdow, status); | |
573 | get_months(dfmt, months, useLongNames, status); | |
574 | ||
b75a7d8f A |
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 | } | |
340931cb | 700 | } |
b75a7d8f A |
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 | ||
340931cb | 748 | } |
b75a7d8f A |
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 */ | |
374ca955 A |
759 | free_months(months); |
760 | free_days(days); | |
b75a7d8f A |
761 | udat_close(dfmt); |
762 | unum_close(nfmt); | |
763 | ucal_close(right_cal); | |
764 | } | |
765 | ||
766 | #endif |