"Fossies" - the Fresh Open Source Software Archive

Member "dateutils-0.4.6/lib/ymcw.c" (19 Mar 2019, 13953 Bytes) of package /linux/privat/dateutils-0.4.6.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ymcw.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.4.5_vs_0.4.6.

    1 /*** ymcw.c -- guts for ymcw dates
    2  *
    3  * Copyright (C) 2010-2019 Sebastian Freundt
    4  *
    5  * Author:  Sebastian Freundt <freundt@ga-group.nl>
    6  *
    7  * This file is part of dateutils.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  *
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  *
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * 3. Neither the name of the author nor the names of any contributors
   21  *    may be used to endorse or promote products derived from this
   22  *    software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   27  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   31  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   33  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   34  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  *
   36  **/
   37 #define ASPECT_YMCW
   38 
   39 #if !defined DEFUN
   40 # define DEFUN
   41 #endif  /* !DEFUN */
   42 
   43 
   44 #if !defined YMCW_ASPECT_HELPERS_
   45 #define YMCW_ASPECT_HELPERS_
   46 
   47 static __attribute__((pure)) unsigned int
   48 __get_mcnt(unsigned int y, unsigned int m, dt_dow_t w)
   49 {
   50 /* get the number of weekdays W in Y-M, which is the max count
   51  * for a weekday W in ymcw dates in year Y and month M */
   52     dt_dow_t wd01 = __get_m01_wday(y, m);
   53     unsigned int md = __get_mdays(y, m);
   54     /* the maximum number of WD01s in Y-M */
   55     unsigned int wd01cnt = (md - 1) / GREG_DAYS_P_WEEK + 1;
   56     /* modulus */
   57     unsigned int wd01mod = (md - 1) % GREG_DAYS_P_WEEK;
   58 
   59     /* now the next WD01MOD days also have WD01CNT occurrences
   60      * if wd01 + wd01mod exceeds the DAYS_PER_WEEK barrier wrap
   61      * around by extending W to W + DAYS_PER_WEEK */
   62     if ((w >= wd01 && w <= wd01 + wd01mod) ||
   63         (w + GREG_DAYS_P_WEEK) <= wd01 + wd01mod) {
   64         return wd01cnt;
   65     } else {
   66         return wd01cnt - 1;
   67     }
   68 }
   69 
   70 DEFUN dt_ymcw_t
   71 __ymcw_fixup(dt_ymcw_t d)
   72 {
   73 /* given dates like 2012-02-05-01 this returns 2012-02-04-01 */
   74     int mc;
   75 
   76     if (LIKELY(d.c <= 4)) {
   77         /* every month has 4 occurrences of any weekday */
   78         ;
   79     } else if (d.m == 0 || d.w == DT_MIRACLEDAY) {
   80         /* um */
   81         ;
   82     } else if (d.c > (mc = __get_mcnt(d.y, d.m, (dt_dow_t)d.w))) {
   83         d.c = mc;
   84     }
   85     return d;
   86 }
   87 #endif  /* YMCW_ASPECT_HELPERS_ */
   88 
   89 
   90 #if defined ASPECT_GETTERS && !defined YMCW_ASPECT_GETTERS_
   91 #define YMCW_ASPECT_GETTERS_
   92 static dt_dow_t
   93 __ymcw_get_wday(dt_ymcw_t that)
   94 {
   95     return (dt_dow_t)(that.w ?: DT_SUNDAY);
   96 }
   97 
   98 DEFUN unsigned int
   99 __ymcw_get_yday(dt_ymcw_t that)
  100 {
  101 /* return the N-th W-day in Y, this is equivalent with 8601's Y-W-D calendar
  102  * where W is the week of the year and D the day in the week */
  103 /* if a year starts on W, then it's
  104  * 5 Ws in jan
  105  * 4 Ws in feb
  106  * 4 Ws in mar
  107  * 5 Ws in apr
  108  * 4 Ws in may
  109  * 4 Ws in jun
  110  * 5 Ws in jul
  111  * 4 Ws in aug
  112  * 4 + leap Ws in sep
  113  * 5 - leap Ws in oct
  114  * 4 Ws in nov
  115  * 5 Ws in dec,
  116  * so go back to the last W, and compute its number instead
  117  *
  118  * Here's the full schema:
  119  * For W+0
  120  * 5 4 4 5 4 4  5 4 4 5 4 5  non-leap
  121  * 5 4 4 5 4 4  5 4 5 4 4 5  leap  flip9
  122  *
  123  * For W+1
  124  * 5 4 4 4 5 4  5 4 4 5 4 4  non-leap
  125  * 5 4 4 5 4 4  5 4 4 5 4 5  leap  flip4  flip12
  126  *
  127  * For W+2
  128  * 5 4 4 4 5 4  4 5 4 5 4 4  non-leap
  129  * 5 4 4 4 5 4  5 4 4 5 4 4  leap  flip7
  130  *
  131  * For W+3
  132  * 4 4 5 4 5 4  4 5 4 4 5 4  non-leap
  133  * 4 5 4 4 5 4  4 5 4 5 4 4  leap  flip2  flip10
  134  *
  135  * For W+4
  136  * 4 4 5 4 4 5  4 5 4 4 5 4  non-leap
  137  * 4 4 5 4 5 4  4 5 4 4 5 4  leap  flip5
  138  *
  139  * For W+5
  140  * 4 4 5 4 4 5  4 4 5 4 4 5  non-leap
  141  * 4 4 5 4 4 5  4 5 4 4 5 4  leap  flip8  flip11
  142  *
  143  * For W+6
  144  * 4 4 4 5 4 4  5 4 5 4 4 5  non-leap
  145  * 4 4 5 4 4 5  4 4 5 4 4 5  leap  flip3  flip6
  146  *
  147  * flipN denotes which month in a leap year becomes 5 where the
  148  * month in the non-leap year equivalent has value 4.
  149  *
  150  * The flips for W+1 W+2, W+4, W+5, W+6 can be presented through
  151  * non-leap rules:
  152  *
  153  * 544544544545544544544545
  154  * 544544545445544544545445
  155  *
  156  * 544454544544544454544544
  157  * 544544544545544544544545 = non-leap W+0
  158  *
  159  * 544454454544544454454544
  160  * 544454544544544454544544 = non-leap W+1
  161  *
  162  * 445454454454445454454454
  163  * 454454454544454454454544
  164  *
  165  * 445445454454445445454454
  166  * 445454454454445454454454 = non-leap W+3
  167  *
  168  * 445445445445445445445445
  169  * 445445454454445445454454 = non-leap W+4
  170  *
  171  * 444544545445444544545445
  172  * 445445445445445445445445 = non-leap W+5
  173  */
  174     static uint8_t ycum[][12] = {
  175         {
  176             /* W+0 */
  177             0, 5, 9, 13, 18, 22, 26,  31, 35, 39, 44, 48, /*53*/
  178         }, {
  179             /* W+1 */
  180             0, 5, 9, 13, 17, 22, 26,  31, 35, 39, 44, 48, /*52*/
  181         }, {
  182             /* W+2 */
  183             0, 5, 9, 13, 17, 22, 26,  30, 35, 39, 44, 48, /*52*/
  184         }, {
  185             /* W+3 */
  186             0, 4, 8, 13, 17, 22, 26,  30, 35, 39, 43, 48, /*52*/
  187         }, {
  188             /* W+4 */
  189             0, 4, 8, 13, 17, 21, 26,  30, 35, 39, 43, 48, /*52*/
  190         }, {
  191             /* W+5 */
  192             0, 4, 8, 13, 17, 21, 26,  30, 34, 39, 43, 47, /*52*/
  193         }, {
  194             /* W+6 */
  195             0, 4, 8, 12, 17, 21, 25,  30, 34, 39, 43, 47, /*52*/
  196         }, {
  197             /* leap-year rule W+0 */
  198             0, 5, 9, 13, 18, 22, 26,  31, 35, 40, 44, 48, /*53*/
  199             /* leap-year rule W+3 = W+0 + 1mo + 4 */
  200         },
  201     };
  202     dt_dow_t j01w = __get_jan01_wday(that.y);
  203     unsigned int diff = j01w <= that.w ? that.w - j01w : that.w + 7 - j01w;
  204 
  205     if (UNLIKELY(__leapp(that.y))) {
  206         switch (diff) {
  207         case 3:
  208             if (UNLIKELY(that.m < 2)) {
  209                 return that.c;
  210             }
  211             return that.c + (ycum[7])[that.m - 2] + 4;
  212         case 0:
  213             return that.c + (ycum[7])[that.m - 1];
  214         default:
  215         case 1:
  216         case 2:
  217         case 4:
  218         case 5:
  219         case 6:
  220             diff--;
  221             break;
  222         }
  223     }
  224     return that.c + (ycum[diff])[that.m - 1];
  225 }
  226 
  227 static unsigned int
  228 __ymcw_get_mday(dt_ymcw_t that)
  229 {
  230     unsigned int wd01;
  231     unsigned int res;
  232 
  233     /* see what weekday the first of the month was*/
  234     wd01 = __get_m01_wday(that.y, that.m);
  235 
  236     /* first WD1 is 1, second WD1 is 8, third WD1 is 15, etc.
  237      * so the first WDx with WDx > WD1 is on (WDx - WD1) + 1 */
  238     res = (that.w + GREG_DAYS_P_WEEK - wd01) % GREG_DAYS_P_WEEK + 1;
  239     res += GREG_DAYS_P_WEEK * (that.c - 1);
  240     /* not all months have a 5th X, so check for this */
  241     if (res > __get_mdays(that.y, that.m)) {
  242          /* 5th = 4th in that case */
  243         res -= GREG_DAYS_P_WEEK;
  244     }
  245     return res;
  246 }
  247 
  248 static int
  249 __ymcw_get_bday(dt_ymcw_t that, dt_bizda_param_t bp)
  250 {
  251     dt_dow_t wd01;
  252     int res;
  253 
  254     switch (that.w) {
  255     case DT_SUNDAY:
  256     case DT_SATURDAY:
  257         return -1;
  258     default:
  259         break;
  260     }
  261     if (bp.ab != BIZDA_AFTER || bp.ref != BIZDA_ULTIMO) {
  262         /* no support yet */
  263         return -1;
  264     }
  265 
  266     /* weekday the month started with */
  267     wd01 = __get_m01_wday(that.y, that.m);
  268     res = (signed int)(that.w - wd01) + DUWW_BDAYS_P_WEEK * (that.c) + 1;
  269     return res;
  270 }
  271 #endif  /* YMCW_ASPECT_GETTERS_ */
  272 
  273 
  274 #if defined ASPECT_CONV && !defined YMCW_ASPECT_CONV_
  275 #define YMCW_ASPECT_CONV_
  276 /* we need some getter stuff, so get it */
  277 #define ASPECT_GETTERS
  278 #include "ymcw.c"
  279 #undef ASPECT_GETTERS
  280 
  281 static dt_ymd_t
  282 __ymcw_to_ymd(dt_ymcw_t d)
  283 {
  284     unsigned int md = __ymcw_get_mday(d);
  285 #if defined HAVE_ANON_STRUCTS_INIT
  286     return (dt_ymd_t){.y = d.y, .m = d.m, .d = md};
  287 #else  /* !HAVE_ANON_STRUCTS_INIT */
  288     dt_ymd_t res;
  289     res.y = d.y;
  290     res.m = d.m;
  291     res.d = md;
  292     return res;
  293 #endif  /* HAVE_ANON_STRUCTS_INIT */
  294 }
  295 
  296 static dt_ywd_t
  297 __ymcw_to_ywd(dt_ymcw_t d)
  298 {
  299     unsigned int y = d.y;
  300     dt_dow_t w = (dt_dow_t)d.w;
  301     unsigned int c = __ymcw_get_yday(d);
  302     return __make_ywd_c(y, c, w, YWD_ABSWK_CNT);
  303 }
  304 
  305 static dt_daisy_t
  306 __ymcw_to_daisy(dt_ymcw_t d)
  307 {
  308     dt_daisy_t res;
  309     unsigned int sy = d.y;
  310     unsigned int sm = d.m;
  311     unsigned int sd;
  312 
  313     if (UNLIKELY((signed int)TO_BASE(sy) < 0)) {
  314         return 0;
  315     }
  316 
  317     sd = __ymcw_get_mday(d);
  318     res = __jan00_daisy(sy);
  319     res += __md_get_yday(sy, sm, sd);
  320     return res;
  321 }
  322 
  323 static dt_yd_t
  324 __ymcw_to_yd(dt_ymcw_t d)
  325 {
  326     unsigned int sd = __ymcw_get_mday(d);
  327     unsigned int sm = d.m;
  328     unsigned int sy = d.y;
  329 
  330 #if defined HAVE_ANON_STRUCTS_INIT
  331     return (dt_yd_t){.y = sy, .d = __md_get_yday(sy, sm, sd)};
  332 #else
  333     dt_yd_t res;
  334     res.y = sy;
  335     res.d = __md_get_yday(sy, sm, sd);
  336     return res;
  337 #endif
  338 }
  339 #endif  /* ASPECT_CONV */
  340 
  341 
  342 #if defined ASPECT_ADD && !defined YMCW_ASPECT_ADD_
  343 #define YMCW_ASPECT_ADD_
  344 
  345 static dt_ymcw_t
  346 __ymcw_fixup_c(unsigned int y, signed int m, signed int c, dt_dow_t w)
  347 {
  348     dt_ymcw_t res = {0};
  349 
  350     /* fixup q */
  351     if (LIKELY(c >= 1 && c <= 4)) {
  352         /* all months in our design range have 4 occurrences of
  353          * any weekday, so YAAAY*/
  354         ;
  355     } else if (c < 1) {
  356         int mc;
  357 
  358         do {
  359             if (UNLIKELY(--m < 1)) {
  360                 --y;
  361                 m = GREG_MONTHS_P_YEAR;
  362             }
  363             mc = __get_mcnt(y, m, w);
  364             c += mc;
  365         } while (c < 1);
  366     } else {
  367         int mc;
  368 
  369         while (c > (mc = __get_mcnt(y, m, w))) {
  370             c -= mc;
  371             if (UNLIKELY(++m > (signed int)GREG_MONTHS_P_YEAR)) {
  372                 ++y;
  373                 m = 1;
  374             }
  375         }
  376     }
  377 
  378     /* final assignment */
  379     res.y = y;
  380     res.m = m;
  381     res.c = c;
  382     res.w = w;
  383     return res;
  384 }
  385 
  386 static dt_ymcw_t
  387 __ymcw_add_w(dt_ymcw_t d, int n)
  388 {
  389 /* add N weeks to D */
  390     signed int tgtc = d.c + n;
  391 
  392     return __ymcw_fixup_c(d.y, d.m, tgtc, (dt_dow_t)d.w);
  393 }
  394 
  395 static dt_ymcw_t
  396 __ymcw_add_d(dt_ymcw_t d, int n)
  397 {
  398 /* add N days to D
  399  * we reduce this to __ymcw_add_w() */
  400     signed int aw = n / (signed int)GREG_DAYS_P_WEEK;
  401     signed int ad = n % (signed int)GREG_DAYS_P_WEEK;
  402 
  403     if ((ad += d.w) >= (signed int)GREG_DAYS_P_WEEK) {
  404         ad -= GREG_DAYS_P_WEEK;
  405         aw++;
  406     } else if (ad < 0) {
  407         ad += GREG_DAYS_P_WEEK;
  408         aw--;
  409     }
  410 
  411     /* fixup for abswk count, m01 may be any wd */
  412     {
  413         dt_dow_t m01 = __get_m01_wday(d.y, d.m);
  414 
  415         if ((dt_dow_t)d.w < m01 && (dt_dow_t)ad >= m01) {
  416             aw++;
  417         } else if ((dt_dow_t)d.w >= m01 && (dt_dow_t)ad < m01) {
  418             aw--;
  419         }
  420     }
  421 
  422     d.w = (dt_dow_t)ad;
  423     return __ymcw_add_w(d, aw);
  424 }
  425 
  426 static dt_ymcw_t
  427 __ymcw_add_b(dt_ymcw_t d, int n)
  428 {
  429 /* add N business days to D */
  430 #if 0
  431 /* trivial trait, reduce to _add_d() problem and dispatch */
  432     dt_dow_t wd = __ymcw_get_wday(d);
  433     return __ymcw_add_d(d, __get_d_equiv(wd, n));
  434 #else
  435     signed int aw = n / (signed int)DUWW_BDAYS_P_WEEK;
  436     signed int ad = n % (signed int)DUWW_BDAYS_P_WEEK;
  437 
  438     if ((ad += d.w) > (signed int)DUWW_BDAYS_P_WEEK) {
  439         ad -= DUWW_BDAYS_P_WEEK;
  440         aw++;
  441     } else if (ad <= 0) {
  442         ad += DUWW_BDAYS_P_WEEK;
  443         aw--;
  444     }
  445 
  446     /* fixup for abswk count, m01 may be any wd */
  447     {
  448         dt_dow_t m01 = __get_m01_wday(d.y, d.m);
  449 
  450         if ((dt_dow_t)d.w < m01 && (dt_dow_t)ad >= m01) {
  451             aw++;
  452         } else if ((dt_dow_t)d.w >= m01 && (dt_dow_t)ad < m01) {
  453             aw--;
  454         }
  455     }
  456 
  457     d.w = (dt_dow_t)ad;
  458     return __ymcw_add_w(d, aw);
  459 #endif
  460 }
  461 
  462 static dt_ymcw_t
  463 __ymcw_add_m(dt_ymcw_t d, int n)
  464 {
  465 /* add N months to D */
  466     signed int tgtm = d.m + n;
  467 
  468     while (tgtm > (signed int)GREG_MONTHS_P_YEAR) {
  469         tgtm -= GREG_MONTHS_P_YEAR;
  470         ++d.y;
  471     }
  472     while (tgtm < 1) {
  473         tgtm += GREG_MONTHS_P_YEAR;
  474         --d.y;
  475     }
  476     /* final assignment */
  477     d.m = tgtm;
  478     return d;
  479 }
  480 
  481 static dt_ymcw_t
  482 __ymcw_add_y(dt_ymcw_t d, int n)
  483 {
  484 /* add N years to D */
  485     d.y += n;
  486     return d;
  487 }
  488 #endif  /* ASPECT_ADD */
  489 
  490 
  491 #if defined ASPECT_DIFF && !defined YMCW_ASPECT_DIFF_
  492 #define YMCW_ASPECT_DIFF_
  493 
  494 static struct dt_ddur_s
  495 __ymcw_diff(dt_ymcw_t d1, dt_ymcw_t d2)
  496 {
  497 /* compute d2 - d1 entirely in terms of ymd */
  498     struct dt_ddur_s res = dt_make_ddur(DT_DURYMCW, 0);
  499     signed int tgtd;
  500     signed int tgtm;
  501     dt_dow_t wd01, wd02;
  502 
  503     if (__ymcw_cmp(d1, d2) > 0) {
  504         dt_ymcw_t tmp = d1;
  505         d1 = d2;
  506         d2 = tmp;
  507         res.neg = 1;
  508     }
  509 
  510     wd01 = __get_m01_wday(d1.y, d1.m);
  511     if (d2.y != d1.y || d2.m != d1.m) {
  512         wd02 = __get_m01_wday(d2.y, d2.m);
  513     } else {
  514         wd02 = wd01;
  515     }
  516 
  517     /* first compute the difference in months Y2-M2-01 - Y1-M1-01 */
  518     tgtm = GREG_MONTHS_P_YEAR * (d2.y - d1.y) + (d2.m - d1.m);
  519     /* using the firsts of the month WD01, represent d1 and d2 as
  520      * the C-th WD01 plus OFF */
  521     {
  522         unsigned int off1;
  523         unsigned int off2;
  524 
  525         off1 = __uimod(d1.w - wd01, GREG_DAYS_P_WEEK);
  526         off2 = __uimod(d2.w - wd02, GREG_DAYS_P_WEEK);
  527         tgtd = off2 - off1 + GREG_DAYS_P_WEEK * (d2.c - d1.c);
  528     }
  529 
  530     /* fixups */
  531     if (tgtd < (signed int)GREG_DAYS_P_WEEK && tgtm > 0) {
  532         /* if tgtm is 0 it remains 0 and tgtd remains negative */
  533         /* get the target month's mdays */
  534         unsigned int d2m = d2.m;
  535         unsigned int d2y = d2.y;
  536 
  537         if (--d2m < 1) {
  538             d2m = GREG_MONTHS_P_YEAR;
  539             d2y--;
  540         }
  541         tgtd += __get_mdays(d2y, d2m);
  542         tgtm--;
  543     }
  544 
  545     /* fill in the results */
  546     res.ymcw.y = tgtm / GREG_MONTHS_P_YEAR;
  547     res.ymcw.m = tgtm % GREG_MONTHS_P_YEAR;
  548     res.ymcw.c = tgtd / GREG_DAYS_P_WEEK;
  549     res.ymcw.w = tgtd % GREG_DAYS_P_WEEK;
  550     return res;
  551 }
  552 #endif  /* ASPECT_DIFF */
  553 
  554 
  555 #if defined ASPECT_CMP && !defined YMCW_ASPECT_CMP_
  556 #define YMCW_ASPECT_CMP_
  557 DEFUN int
  558 __ymcw_cmp(dt_ymcw_t d1, dt_ymcw_t d2)
  559 {
  560     if (d1.y < d2.y) {
  561         return -1;
  562     } else if (d1.y > d2.y) {
  563         return 1;
  564     } else if (d1.m < d2.m) {
  565         return -1;
  566     } else if (d1.m > d2.m) {
  567         return 1;
  568     }
  569 
  570     /* we're down to counts, however, the last W of a month is always
  571      * count 5, even though counting forward it would be 4 */
  572     if (d1.c < d2.c) {
  573         return -1;
  574     } else if (d1.c > d2.c) {
  575         return 1;
  576     }
  577     /* now it's up to the first of the month */
  578     {
  579         dt_dow_t wd01;
  580         unsigned int off1;
  581         unsigned int off2;
  582 
  583         wd01 = __get_m01_wday(d1.y, d1.m);
  584         /* represent cw as C-th WD01 + OFF */
  585         off1 = __uimod(d1.w - wd01, GREG_DAYS_P_WEEK);
  586         off2 = __uimod(d2.w - wd01, GREG_DAYS_P_WEEK);
  587 
  588         if (off1 < off2) {
  589             return -1;
  590         } else if (off1 > off2) {
  591             return 1;
  592         } else {
  593             return 0;
  594         }
  595     }
  596 }
  597 #endif  /* ASPECT_CMP */
  598 
  599 
  600 #if defined ASPECT_STRF && !defined YMCW_ASPECT_STRF_
  601 #define YMCW_ASPECT_STRF_
  602 
  603 #endif  /* ASPECT_STRF */
  604 
  605 /* ymcw.c ends here */