home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 March / PCWorld_2003-03_cd.bin / Software / Vyzkuste / openoffice / f_0314 / xdfa.c < prev    next >
C/C++ Source or Header  |  2002-10-25  |  28KB  |  1,032 lines

  1. /*------------------------------------------------------------------------
  2.  
  3. $Workfile:   DFA.CL  $
  4.  
  5. $Header: /cvs/oo/sc/sc/addin/datefunc/dfa.cl,v 1.1.1.1 2000/09/18 16:44:46 hr Exp $
  6.  
  7. Description:    StarCalc Datefunc AddIn Example
  8.  
  9. (c) Copyright 1998 - 2000, Sun Microsystems, Inc.
  10.  
  11. ------------------------------------------------------------------------*/
  12.  
  13. static char datefunc_Id[]="@(#) StarCalc Datefunc AddIn (c) 1998-2000 Sun Microsystems, Inc.";
  14.  
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <math.h>
  18.  
  19. #include <xlang.h>
  20. #include <addin.h>
  21. #include <dfa.hrc>
  22.  
  23.  
  24. /**
  25.  * the current language the Addin is using
  26.  */
  27. static USHORT _nLanguage=LANGUAGE_ENGLISH;
  28.  
  29.  
  30. /**
  31.  * Get text resource for current language.
  32.  * Remember that 8-bit characters are shown in
  33.  * system dependend code pages!
  34.  * To get correct results you will have to distuinguish
  35.  * for example between UNIX and WIN and OS2 target systems.
  36.  */
  37. static char* getText( int nResource )
  38. {
  39.     switch( nResource ) {
  40.         case DFA_PAR_DATE1_NAME:
  41.             switch( _nLanguage ) {
  42.                 case LANGUAGE_GERMAN:
  43.                 return( "Datum 1" );
  44.                 case LANGUAGE_ENGLISH:
  45.                 default:
  46.                 return( "Date 1");
  47.             }
  48.             break;
  49.         case DFA_PAR_DATE2_NAME:
  50.             switch( _nLanguage ) {
  51.                 case LANGUAGE_GERMAN:
  52.                 return( "Datum 2" );
  53.                 case LANGUAGE_ENGLISH:
  54.                 default:
  55.                 return( "Date 2");
  56.             }
  57.             break;
  58.         case DFA_PAR_MODE_NAME:
  59.             switch( _nLanguage ) {
  60.                 case LANGUAGE_GERMAN:
  61.                 return( "Art" );
  62.                 case LANGUAGE_ENGLISH:
  63.                 default:
  64.                 return( "Mode");
  65.             }
  66.             break;
  67.         case DFA_PAR_DATE_NAME:
  68.             switch( _nLanguage ) {
  69.                 case LANGUAGE_GERMAN:
  70.                 return( "Datum" );
  71.                 case LANGUAGE_ENGLISH:
  72.                 default:
  73.                 return( "Date");
  74.             }
  75.             break;
  76.         case DFA_PAR_DATE_DESC:
  77.             switch( _nLanguage ) {
  78.                 case LANGUAGE_GERMAN:
  79.                 return( "Interne Zahl des Datums" );
  80.                 case LANGUAGE_ENGLISH:
  81.                 default:
  82.                 return( "Internal number of the date");
  83.             }
  84.             break;
  85.         case DFA_WEEK_NAME:
  86.             switch( _nLanguage ) {
  87.                 case LANGUAGE_GERMAN:
  88.                 return( "Wochen" );
  89.                 case LANGUAGE_ENGLISH:
  90.                 default:
  91.                 return( "Weeks");
  92.             }
  93.             break;
  94.         case DFA_WEEK_DESC:
  95.             switch( _nLanguage ) {
  96.                 case LANGUAGE_GERMAN:
  97.                 return( "Bestimmt die Wochendifferenz zweier Daten" );
  98.                 case LANGUAGE_ENGLISH:
  99.                 default:
  100.                 return( "Returns the difference in weeks between two dates");
  101.             }
  102.             break;
  103.         case DFA_WEEK_PAR1_DESC:
  104.             switch( _nLanguage ) {
  105.                 case LANGUAGE_GERMAN:
  106.                 return( "J\374ngeres Datum f\374r die Wochendifferenz" );
  107.                 case LANGUAGE_ENGLISH:
  108.                 default:
  109.                 return( "The end date for calculating the difference in weeks");
  110.             }
  111.             break;
  112.         case DFA_WEEK_PAR2_DESC:
  113.             switch( _nLanguage ) {
  114.                 case LANGUAGE_GERMAN:
  115.                 return( "\304lteres Datum f\374r die Wochendifferenz" );
  116.                 case LANGUAGE_ENGLISH:
  117.                 default:
  118.                 return( "The start date for calculating the difference weeks");
  119.             }
  120.             break;
  121.         case DFA_WEEK_PAR3_DESC:
  122.             switch( _nLanguage ) {
  123.                 case LANGUAGE_GERMAN:
  124.                 return( "Art der Differenzbildung Art=0 hei\337t Intervall, Art=1 hei\337t in Kalenderwochen" );
  125.                 case LANGUAGE_ENGLISH:
  126.                 default:
  127.                 return( "Type of difference calculation: mode=0 means the interval, mode=1 means calendar weeks");
  128.             }
  129.             break;
  130.         case DFA_MONTHS_NAME:
  131.             switch( _nLanguage ) {
  132.                 case LANGUAGE_GERMAN:
  133.                 return( "Monate" );
  134.                 case LANGUAGE_ENGLISH:
  135.                 default:
  136.                 return( "Months");
  137.             }
  138.             break;
  139.         case DFA_MONTHS_DESC:
  140.             switch( _nLanguage ) {
  141.                 case LANGUAGE_GERMAN:
  142.                 return( "Bestimmt die Monatsdifferenz zweier Daten" );
  143.                 case LANGUAGE_ENGLISH:
  144.                 default:
  145.                 return( "Determines the number of months between two dates");
  146.             }
  147.             break;
  148.         case DFA_MONTHS_PAR1_DESC:
  149.             switch( _nLanguage ) {
  150.                 case LANGUAGE_GERMAN:
  151.                 return( "J\374ngeres Datum f\374r die Monatsdifferenz" );
  152.                 case LANGUAGE_ENGLISH:
  153.                 default:
  154.                 return( "The end date for calculating the difference in months");
  155.             }
  156.             break;
  157.         case DFA_MONTHS_PAR2_DESC:
  158.             switch( _nLanguage ) {
  159.                 case LANGUAGE_GERMAN:
  160.                 return( "\304lteres Datum f\374r die Monatsdifferenz" );
  161.                 case LANGUAGE_ENGLISH:
  162.                 default:
  163.                 return( "The start date for calculating the difference in months");
  164.             }
  165.             break;
  166.         case DFA_MONTHS_PAR3_DESC:
  167.             switch( _nLanguage ) {
  168.                 case LANGUAGE_GERMAN:
  169.                 return( "Art der Differenzbildung Art=0 hei\337t Intervall, Art=1 hei\337t in Kalendermonaten" );
  170.                 case LANGUAGE_ENGLISH:
  171.                 default:
  172.                 return( "Type of difference calculation: Mode = 0 means interval, mode = 1 means in calendar months");
  173.             }
  174.             break;
  175.         case DFA_YEARS_NAME:
  176.             switch( _nLanguage ) {
  177.                 case LANGUAGE_GERMAN:
  178.                 return( "Jahre" );
  179.                 case LANGUAGE_ENGLISH:
  180.                 default:
  181.                 return( "Years");
  182.             }
  183.             break;
  184.         case DFA_YEARS_DESC:
  185.             switch( _nLanguage ) {
  186.                 case LANGUAGE_GERMAN:
  187.                 return( "Bestimmt die Jahresdifferenz zweier Daten" );
  188.                 case LANGUAGE_ENGLISH:
  189.                 default:
  190.                 return( "Returns the difference in years between two dates");
  191.             }
  192.             break;
  193.         case DFA_YEARS_PAR1_DESC:
  194.             switch( _nLanguage ) {
  195.                 case LANGUAGE_GERMAN:
  196.                 return( "J\374ngeres Datum f\374r die Jahresdifferenz" );
  197.                 case LANGUAGE_ENGLISH:
  198.                 default:
  199.                 return( "The end date for calculating the difference in years");
  200.             }
  201.             break;
  202.         case DFA_YEARS_PAR2_DESC:
  203.             switch( _nLanguage ) {
  204.                 case LANGUAGE_GERMAN:
  205.                 return( "\304lteres Datum f\374r die Jahresdifferenz" );
  206.                 case LANGUAGE_ENGLISH:
  207.                 default:
  208.                 return( "The start date for calculating the difference in years");
  209.             }
  210.             break;
  211.         case DFA_YEARS_PAR3_DESC:
  212.             switch( _nLanguage ) {
  213.                 case LANGUAGE_GERMAN:
  214.                 return( "Art der Differenzbildung Art=0 hei\337t Intervall, Art=1 hei\337t in Kalenderjahren" );
  215.                 case LANGUAGE_ENGLISH:
  216.                 default:
  217.                 return( "Type of difference calculation: Mode=0 means interval, mode=1 means in calendar years.");
  218.             }
  219.             break;
  220.         case DFA_ISLEAPYEAR_NAME:
  221.             switch( _nLanguage ) {
  222.                 case LANGUAGE_GERMAN:
  223.                 return( "IstSchaltJahr" );
  224.                 case LANGUAGE_ENGLISH:
  225.                 default:
  226.                 return( "IsLeapYear");
  227.             }
  228.             break;
  229.         case DFA_ISLEAPYEAR_DESC:
  230.             switch( _nLanguage ) {
  231.                 case LANGUAGE_GERMAN:
  232.                 return( "Liefert 1(WAHR) wenn das Jahr ein Schaltjahr ist sonst 0(FALSCH)" );
  233.                 case LANGUAGE_ENGLISH:
  234.                 default:
  235.                 return( "Returns 1 (TRUE) if a leap year is used, otherwise 0 (FALSE) is returned");
  236.             }
  237.             break;
  238.         case DFA_DAYSINMONTH_NAME:
  239.             switch( _nLanguage ) {
  240.                 case LANGUAGE_GERMAN:
  241.                 return( "TageImMonat" );
  242.                 case LANGUAGE_ENGLISH:
  243.                 default:
  244.                 return( "DaysInMonth");
  245.             }
  246.             break;
  247.         case DFA_DAYSINMONTH_DESC:
  248.             switch( _nLanguage ) {
  249.                 case LANGUAGE_GERMAN:
  250.                 return( "Bestimmt die Anzahl an Tagen im Monat zu einem Datum" );
  251.                 case LANGUAGE_ENGLISH:
  252.                 default:
  253.                 return( "Returns the number of days in the month in relation to the date entered");
  254.             }
  255.             break;
  256.         case DFA_DAYSINYEAR_NAME:
  257.             switch( _nLanguage ) {
  258.                 case LANGUAGE_GERMAN:
  259.                 return( "TageImJahr" );
  260.                 case LANGUAGE_ENGLISH:
  261.                 default:
  262.                 return( "DaysInYear");
  263.             }
  264.             break;
  265.         case DFA_DAYSINYEAR_DESC:
  266.             switch( _nLanguage ) {
  267.                 case LANGUAGE_GERMAN:
  268.                 return( "Bestimmt die Anzahl an Tagen im Jahr zu einem Datum" );
  269.                 case LANGUAGE_ENGLISH:
  270.                 default:
  271.                 return( "Returns the number of days in a year in relation to the date entered");
  272.             }
  273.             break;
  274.         case DFA_WEEKSINYEAR_NAME:
  275.             switch( _nLanguage ) {
  276.                 case LANGUAGE_GERMAN:
  277.                 return( "WochenImJahr" );
  278.                 case LANGUAGE_ENGLISH:
  279.                 default:
  280.                 return( "WeeksInYear");
  281.             }
  282.             break;
  283.         case DFA_WEEKSINYEAR_DESC:
  284.             switch( _nLanguage ) {
  285.                 case LANGUAGE_GERMAN:
  286.                 return( "Bestimmt die Anzahl an Wochen im Jahr zu einem Datum" );
  287.                 case LANGUAGE_ENGLISH:
  288.                 default:
  289.                 return( "Returns the number of weeks in the year in relation to a date");
  290.             }
  291.             break;
  292.         default:
  293.             break;
  294.     }
  295.     return("");
  296. }
  297.  
  298.  
  299. /**
  300.  * Get neutral language for specific language.
  301.  * This simplifies the getText switch cases and allows to handle
  302.  * previously unknown language derivates due to foreign installations.
  303.  * If you want to distinguish between some dialects change this function
  304.  * to return the desired nLang before doing the bit masking stuff.
  305.  * See xlang.h for defined LANGUAGE_*
  306.  */
  307. static USHORT GetNeutralLanguage( USHORT nLang )
  308. {
  309.     USHORT nPrimLang;
  310.  
  311.     /* ignore LANGUAGE_USER* */
  312.     if ( (nLang & 0x03FF) >= 0x0200 )
  313.         return nLang;
  314.  
  315.     nLang &= 0x03FF;
  316.  
  317.     nPrimLang = nLang | 0x0400;
  318.  
  319.     switch ( nPrimLang )
  320.     {
  321.         case LANGUAGE_CHINESE_TRADITIONAL:
  322.             nLang = LANGUAGE_CHINESE;
  323.             break;
  324.         case LANGUAGE_ENGLISH_US:
  325.             nLang = LANGUAGE_ENGLISH;
  326.             break;
  327.         case LANGUAGE_NORWEGIAN_BOKMAL:
  328.             nLang = LANGUAGE_NORWEGIAN;
  329.             break;
  330.         case LANGUAGE_PORTUGUESE_BRAZILIAN:
  331.             nLang = LANGUAGE_PORTUGUESE;
  332.             break;
  333.  
  334.         default:
  335.             nLang = nPrimLang;
  336.             break;
  337.     }
  338.  
  339.     return nLang;
  340. }
  341.  
  342.  
  343. /**
  344.  * StarCalc calls this function to set a new current Language for the Addin
  345.  *
  346.  * @param *nLanguage
  347.  *
  348.  */
  349. void CALLTYPE SetLanguage( USHORT* nLanguage )
  350. {
  351.     _nLanguage = GetNeutralLanguage( *nLanguage );
  352. }
  353.  
  354.  
  355. /**
  356.  * Null Date, initialized in GetFunctionCount
  357.  *
  358.  * StarCalc uses a BaseDate 12/30/1899
  359.  * If not specified otherwise in the Settings for the Spreedsheet Document.
  360.  *
  361.  * There's no way to get the Spreadsheet settings from whithin a simple addin,
  362.  * so this Addin can only be used by documents using the default BaseDate setting.
  363.  *
  364.  * The functions in this Addin use a BaseDate 01/01/0001
  365.  * The nNullDate Variable is the StarCalc BaseDate converted to
  366.  * this internal date representation.
  367.  *
  368.  * @see #GetFunctionCount
  369.  *
  370.  */
  371.  
  372. static ULONG nNullDate=0;
  373.  
  374. #define NULLDATE_Year  1899
  375. #define NULLDATE_Month 12
  376. #define NULLDATE_Day   30
  377.  
  378.  
  379. /**
  380.  * Array holding values for month length, used in DaysInMonth() function
  381.  *
  382.  * @see #DaysInMonth
  383.  *
  384.  */
  385. static USHORT aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
  386.                                    31, 31, 30, 31, 30, 31 };
  387.  
  388. /**
  389.  * Check if a year is a leap year in the Gregorian calendar
  390.  *
  391.  * @param nYear the year which should be checked
  392.  * @return true if the year is a leap year, false otherwise.
  393.  *
  394.  * @see #DaysInMonth, #IsLeapYear,
  395.  * @see #ScDate_DaysInMonth, #ScDate_IsLeapYear, #ScDate_WeeksInYear
  396.  *
  397.  */
  398. static BOOL IsLeapYear( USHORT nYear )
  399. {
  400.     return (((nYear % 4) == 0) && ((nYear % 100) != 0) || ((nYear % 400) == 0));
  401. }
  402.  
  403.  
  404. /**
  405.  * Get the number of days in a specified month
  406.  *
  407.  * @param nMonth the number of the Month
  408.  * @param nYear the year
  409.  * @return number of days
  410.  *
  411.  */
  412. static USHORT DaysInMonth( USHORT nMonth, USHORT nYear )
  413. {
  414.     if ( nMonth != 2 )
  415.         return aDaysInMonth[nMonth-1];
  416.     else
  417.     {
  418.         if ( IsLeapYear(nYear) )
  419.             return aDaysInMonth[nMonth-1] + 1;
  420.         else
  421.             return aDaysInMonth[nMonth-1];
  422.     }
  423. }
  424.  
  425.  
  426. /**
  427.  * Convert a date to a count of days starting from 01/01/0001
  428.  *
  429.  * The internal representation of a Date used in this Addin
  430.  * is the number of days between 01/01/0001 and the date
  431.  * this function converts a Day , Month, Year representation
  432.  * to this internal Date value.
  433.  *
  434.  * @param nDay the day of the Month
  435.  * @param nMonth the number of the Month
  436.  * @param nYear the Year
  437.  * @return count of days from 01/01/0001 to the date specified
  438.  *
  439.  */
  440. static long DateToDays( USHORT nDay, USHORT nMonth, USHORT nYear )
  441. {
  442.     long nDays;
  443.     USHORT i;
  444.  
  445.     nDays = ((ULONG)nYear-1) * 365;
  446.     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
  447.  
  448.     for( i = 1; i < nMonth; i++ )
  449.         nDays += DaysInMonth(i,nYear);
  450.     nDays += nDay;
  451.  
  452.     return nDays;
  453. }
  454.  
  455.  
  456. /**
  457.  * Convert a count of days starting from 01/01/0001 to a date
  458.  *
  459.  * The internal representation of a Date used in this Addin
  460.  * is the number of days between 01/01/0001 and the date
  461.  * this function converts this internal Date value
  462.  * to a Day , Month, Year representation of a Date.
  463.  *
  464.  * @param nDay count of days from 01/01/0001
  465.  * @param *pDay pointer to a variable for the day of the month
  466.  * @param *pMonth pointer to a variable for the month
  467.  * @param *pYear pointer to a variable for the year
  468.  *
  469.  */
  470. static void DaysToDate( long nDays,
  471.                         USHORT *pDay, USHORT *pMonth, USHORT *pYear )
  472. {
  473.     long    nTempDays;
  474.     long    i = 0;
  475.     BOOL    bCalc;
  476.  
  477.     do
  478.     {
  479.         nTempDays = (long)nDays;
  480.         *pYear = (USHORT)((nTempDays / 365) - i);
  481.         nTempDays -= ((ULONG) *pYear -1) * 365;
  482.         nTempDays -= (( *pYear -1) / 4) - (( *pYear -1) / 100) + ((*pYear -1) / 400);
  483.         bCalc = FALSE;
  484.         if ( nTempDays < 1 )
  485.         {
  486.             i++;
  487.             bCalc = TRUE;
  488.         }
  489.         else
  490.         {
  491.             if ( nTempDays > 365 )
  492.             {
  493.                 if ( (nTempDays != 366) || !IsLeapYear( *pYear ) )
  494.                 {
  495.                     i--;
  496.                     bCalc = TRUE;
  497.                 }
  498.             }
  499.         }
  500.     }
  501.     while ( bCalc );
  502.  
  503.     *pMonth = 1;
  504.     while ( (ULONG)nTempDays > DaysInMonth( *pMonth, *pYear ) )
  505.     {
  506.         nTempDays -= DaysInMonth( *pMonth, *pYear );
  507.         (*pMonth)++;
  508.     }
  509.     *pDay = (USHORT)nTempDays;
  510. }
  511.  
  512. /**
  513.  * Get week difference between 2 dates
  514.  *
  515.  * new Weeks(date1,date2,mode) function for StarCalc
  516.  *
  517.  * Two modes of operation are provided.
  518.  * The first is just a simple division by 7 calculation.
  519.  *
  520.  * The second calculates the diffence by week of year.
  521.  *
  522.  * The International Standard IS-8601 has decreed that Monday
  523.  * shall be the first day of the week.
  524.  *
  525.  * A week that lies partly in one year and partly in annother
  526.  * is assigned a number in the the year in which most of its days lie.
  527.  *
  528.  * That means that week 1 of any year is the week that contains the 4. January
  529.  *
  530.  * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
  531.  *
  532.  * A WeekDay can be then calculated by substracting 1 and calculating the rest of
  533.  * a division by 7, which gives a 0 - 6 value for Monday - Sunday
  534.  *
  535.  * Using the 4. January rule explained above the formula
  536.  *
  537.  *    nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
  538.  *
  539.  * calculates a number between 0-53 for each day which is in the same year as nJan4
  540.  * where 0 means that this week belonged to the year before.
  541.  *
  542.  * If a day in the same or annother year is used in this formula this calculates
  543.  * an calendar week offset from a given 4. January
  544.  *
  545.  *    nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
  546.  *
  547.  * The 4.January of first Date Argument can thus be used to calculate
  548.  * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
  549.  *
  550.  * which can be optimized to
  551.  *
  552.  * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
  553.  *
  554.  * Note: All calculations are operating on the long integer data type
  555.  * % is the modulo operator in C which calculates the rest of an Integer division
  556.  *
  557.  *
  558.  * @param *r - return value for the StarCalc function
  559.  * @param d1 - date value (in StarCalc representation based 12/30/1899), usually the older date
  560.  * @param d2 - date value (in StarCalc representation based 12/30/1899), usually the younger date
  561.  * @param dMode - mode of operation
  562.  *
  563.  * mode 0 is the interval between the dates in month, that is days / 7
  564.  *
  565.  * mode 1 is the difference by week of year
  566.  *
  567.  */
  568. void CALLTYPE ScDate_GetDiffWeeks(double *r, double *d1, double *d2, double *dMode)
  569. {
  570.   long nDays1=0;
  571.   long nDays2=0;
  572.   int nMode=0;
  573.  
  574.   if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
  575.   if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
  576.  
  577.  
  578.   if ( dMode) nMode=(int)*dMode;
  579.  
  580.   if ( nMode == 1 ) {
  581.  
  582.     USHORT nDay,nMonth,nYear;
  583.     long nJan4;
  584.  
  585.     DaysToDate(nDays1,&nDay,&nMonth,&nYear);
  586.     nJan4=DateToDays(4,1,nYear);
  587.  
  588.     *r=(double) ( ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ) );
  589.  
  590.   } else {
  591.  
  592.     *r= (double) ( (nDays2 - nDays1) / 7 ) ;
  593.   }
  594.  
  595. }
  596.  
  597. /**
  598.  * Get month difference between 2 dates
  599.  * =Month(start, end, mode) Function for StarCalc
  600.  *
  601.  * two modes are provided
  602.  *
  603.  * @param *r - return value for the StarCalc function
  604.  * @param d1 - date value, start date
  605.  * @param d2 - date value, end date
  606.  * @param dMode - mode of operation
  607.  *
  608.  * mode 0 is the interval between the dates in month
  609.  *
  610.  * mode 1 is the difference in calendar month
  611.  *
  612.  */
  613. void CALLTYPE ScDate_GetDiffMonths(double *r, double *d1, double *d2, double *dMode)
  614. {
  615.   USHORT nDay1,nMonth1,nYear1;
  616.   USHORT nDay2,nMonth2,nYear2;
  617.   long nDays1=0;
  618.   long nDays2=0;
  619.   int nMode=0;
  620.  
  621.   if ( dMode) nMode=(int)*dMode;
  622.  
  623.   if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
  624.   if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
  625.  
  626.   DaysToDate(nDays1,&nDay1,&nMonth1,&nYear1);
  627.   DaysToDate(nDays2,&nDay2,&nMonth2,&nYear2);
  628.  
  629.   *r=(double) ( nMonth2 - nMonth1 + (nYear2 - nYear1) * 12 );
  630.   if ( nMode == 1 || nDays1 == nDays2 ) return;
  631.  
  632.   if ( nDays1 < nDays2 ) {
  633.     if ( nDay1 > nDay2 ) {
  634.         *r -= 1;
  635.     }
  636.   } else {
  637.     if ( nDay1 < nDay2 ) {
  638.         *r += 1;
  639.     }
  640.   }
  641.  
  642. }
  643.  
  644.  
  645. /**
  646.  * Get Year difference between 2 dates
  647.  *
  648.  * two modes are provided
  649.  *
  650.  * @param *r - return value for the StarCalc function
  651.  * @param d1 - date value, start date
  652.  * @param d2 - date value, end date
  653.  * @param dMode - mode of operation
  654.  *
  655.  * mode 0 is the interval between the dates in years
  656.  *
  657.  * mode 1 is the difference in calendar years
  658.  *
  659.  */
  660. void CALLTYPE ScDate_GetDiffYears(double *r, double *d1, double *d2, double *dMode)
  661. {
  662.   USHORT nDay1,nMonth1,nYear1;
  663.   USHORT nDay2,nMonth2,nYear2;
  664.   long nDays1=0;
  665.   long nDays2=0;
  666.   int nMode=0;
  667.  
  668.   if ( dMode) nMode=(int)*dMode;
  669.  
  670.   if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
  671.   if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
  672.  
  673.   DaysToDate(nDays1,&nDay1,&nMonth1,&nYear1);
  674.   DaysToDate(nDays2,&nDay2,&nMonth2,&nYear2);
  675.   if ( nMode != 1 ) {
  676.     ScDate_GetDiffMonths(r,d1,d2,dMode);
  677.     *r= (double) ( ((int) *r) / 12 );
  678.   } else {
  679.       *r=(double) ( nYear2 - nYear1 );
  680.   }
  681. }
  682.  
  683. /**
  684.  * Check if a Date is in a leap year in the Gregorian calendar
  685.  *
  686.  * @param *r - return value for the StarCalc function
  687.  * @param d - date value (in StarCalc representation based 12/30/1899)
  688.  *
  689.  */
  690. void CALLTYPE ScDate_IsLeapYear(double *r, double *d)
  691. {
  692.   ULONG nDays;
  693.   USHORT nDay, nMonth, nYear;
  694.   double v=0.0;
  695.  
  696.   if ( d ) v=*d;
  697.   nDays=(int) v + nNullDate;
  698.  
  699.   DaysToDate(nDays,&nDay,&nMonth,&nYear);
  700.  
  701.   *r=(double) ( IsLeapYear(nYear) );
  702.  
  703. }
  704.  
  705. /**
  706.  * Get the Number of Days in the month for a date
  707.  *
  708.  * @param *r - return value for the StarCalc function
  709.  * @param d - date value (in StarCalc representation based 12/30/1899)
  710.  *
  711.  */
  712. void CALLTYPE ScDate_DaysInMonth(double *r, double *d)
  713. {
  714.   ULONG nDays;
  715.   USHORT nDay, nMonth, nYear;
  716.   double v=0.0;
  717.  
  718.   if ( d ) v=*d;
  719.   nDays=(int) v + nNullDate;
  720.  
  721.   DaysToDate(nDays,&nDay,&nMonth,&nYear);
  722.   *r=(double) ( DaysInMonth( nMonth, nYear) );
  723.  
  724. }
  725.  
  726.  
  727. /**
  728.  * Get number of weeks in the year for a date
  729.  *
  730.  * Most years have 52 weeks, but years that start on a Thursday
  731.  * and leep years that start on a Wednesday have 53 weeks
  732.  *
  733.  * The International Standard IS-8601 has decreed that Monday
  734.  * shall be the first day of the week.
  735.  *
  736.  * A WeekDay can be calculated by substracting 1 and calculating the rest of
  737.  * a division by 7 from the internal date represention
  738.  * which gives a 0 - 6 value for Monday - Sunday
  739.  *
  740.  * @param *r - return value for the StarCalc function
  741.  * @param d - date value (in StarCalc represantaion based 30.12.1899)
  742.  *
  743.  * @see #IsLeapYear #WeekNumber
  744.  *
  745.  */
  746. void CALLTYPE ScDate_WeeksInYear(double *r, double *d)
  747. {
  748.   ULONG nDays;
  749.   USHORT nDay, nMonth, nYear;
  750.   double v=0.0;
  751.   long nJan1WeekDay;
  752.  
  753.   if ( d ) v=*d;
  754.   nDays=(int) v + nNullDate;
  755.  
  756.   DaysToDate(nDays,&nDay,&nMonth,&nYear);
  757.  
  758.   nJan1WeekDay= ( DateToDays(1,1,nYear) - 1) % 7;
  759.  
  760.   if ( nJan1WeekDay == 3 ) { /* Thursday */
  761.     *r=(double) 53;
  762.     return;
  763.   } else if ( nJan1WeekDay == 2 ) { /* Wednesday */
  764.     *r= (double) ( IsLeapYear(nYear) ? 53 : 52 );
  765.   } else {
  766.     *r= (double) 52;
  767.   }
  768. }
  769.  
  770.  
  771. /**
  772.  * Get number of days in the year of a date specified
  773.  *
  774.  * @param *r - return value for the StarCalc function
  775.  * @param d - date value (in StarCalc represantaion based 30.12.1899)
  776.  *
  777.  */
  778. void CALLTYPE ScDate_DaysInYear(double *r, double *d)
  779. {
  780.   ULONG nDays;
  781.   USHORT nDay, nMonth, nYear;
  782.   double v=0.0;
  783.  
  784.   if ( d ) v=*d;
  785.   nDays=(int) v + nNullDate;
  786.  
  787.   DaysToDate(nDays,&nDay,&nMonth,&nYear);
  788.   *r=(double) ( IsLeapYear(nYear) ? 366 : 365 );
  789.  
  790. }
  791.  
  792.  
  793. /**
  794.  * Tell StarCalc how many new functions this Addin provides.
  795.  *
  796.  * It's called before any of these new functions is actually
  797.  * executed and is also used to initialize the NullDate here.
  798.  *
  799.  * StarCalc uses a Date Base 12/30/1899
  800.  * If not specified otherwise in the Options for the Spreedsheet Document
  801.  *
  802.  *
  803.  * @param *nCount - returns the number of functions which are exported to StarCalc
  804.  *
  805.  */
  806. void CALLTYPE GetFunctionCount( USHORT *nCount )
  807. {
  808.  
  809.   /* initialize nNullDate Value 0 is 12/30/1899 */
  810.   nNullDate=DateToDays(NULLDATE_Day, NULLDATE_Month, NULLDATE_Year);
  811.  
  812.   *nCount = 7;
  813. }
  814.  
  815. /**
  816.  * Provides neccessary data for each new function to StarCalc
  817.  *
  818.  * @param *nNo Input: Function number between 0 and nCount - 1
  819.  * @param *pFuncName Output: Functionname which should be called in the AddIn-DLL
  820.  * @param *nParamCount Output: Number of Parameter. Must be greater than 0, because there's always a return-Value. Maximum is 16.
  821.  * @param *peType Output: Pointer to arrray with exactly 16 variables of typ Paramtype. nParamCount Entries are set to the type of the corresponding Parameters.
  822.  * @param *pInternalName Output: Functionname as seen by the Spreadsheet user
  823.  *
  824.  * @see #GetFunctionCount, #GetParameterDescription
  825.  *
  826.  */
  827. void CALLTYPE GetFunctionData( USHORT *    nNo,
  828.                                char *      pFuncName,
  829.                                USHORT *    nParamCount,
  830.                                ParamType * peType,
  831.                                char *      pInternalName )
  832. {
  833.  
  834.  
  835.      switch( *nNo ) {
  836.      case 0:
  837.      SO_StringCopy( pInternalName, getText(DFA_WEEK_NAME) );
  838.      SO_StringCopy( pFuncName,     "ScDate_GetDiffWeeks" );
  839.      peType[0] = PTR_DOUBLE;
  840.      peType[1] = PTR_DOUBLE;
  841.      peType[2] = PTR_DOUBLE;
  842.      peType[3] = PTR_DOUBLE;
  843.      *nParamCount=4;
  844.      break;
  845.  
  846.      case 1:
  847.      SO_StringCopy( pInternalName, getText(DFA_MONTHS_NAME) );
  848.      SO_StringCopy( pFuncName,     "ScDate_GetDiffMonths" );
  849.      peType[0] = PTR_DOUBLE;
  850.      peType[1] = PTR_DOUBLE;
  851.      peType[2] = PTR_DOUBLE;
  852.      peType[3] = PTR_DOUBLE;
  853.      *nParamCount=4;
  854.      break;
  855.  
  856.      case 2:
  857.      SO_StringCopy( pInternalName, getText(DFA_YEARS_NAME) );
  858.      SO_StringCopy( pFuncName,     "ScDate_GetDiffYears" );
  859.      peType[0] = PTR_DOUBLE;
  860.      peType[1] = PTR_DOUBLE;
  861.      peType[2] = PTR_DOUBLE;
  862.      peType[3] = PTR_DOUBLE;
  863.      *nParamCount=4;
  864.      break;
  865.  
  866.      case 3:
  867.      SO_StringCopy( pInternalName, getText(DFA_ISLEAPYEAR_NAME) );
  868.      SO_StringCopy( pFuncName,     "ScDate_IsLeapYear" );
  869.      peType[0] = PTR_DOUBLE;
  870.      peType[1] = PTR_DOUBLE;
  871.      *nParamCount=2;
  872.      break;
  873.  
  874.      case 4:
  875.      SO_StringCopy( pInternalName, getText(DFA_DAYSINMONTH_NAME) );
  876.      SO_StringCopy( pFuncName,     "ScDate_DaysInMonth" );
  877.      peType[0] = PTR_DOUBLE;
  878.      peType[1] = PTR_DOUBLE;
  879.      *nParamCount=2;
  880.      break;
  881.  
  882.      case 5:
  883.      SO_StringCopy( pInternalName, getText(DFA_DAYSINYEAR_NAME) );
  884.      SO_StringCopy( pFuncName,     "ScDate_DaysInYear" );
  885.      peType[0] = PTR_DOUBLE;
  886.      peType[1] = PTR_DOUBLE;
  887.      *nParamCount=2;
  888.      break;
  889.  
  890.      case 6:
  891.      SO_StringCopy( pInternalName, getText(DFA_WEEKSINYEAR_NAME) );
  892.      SO_StringCopy( pFuncName,     "ScDate_WeeksInYear" );
  893.      peType[0] = PTR_DOUBLE;
  894.      peType[1] = PTR_DOUBLE;
  895.      *nParamCount=2;
  896.      break;
  897.  
  898.      default:
  899.             *nParamCount    = 0;
  900.             *pFuncName     = 0;
  901.             *pInternalName = 0;
  902.             break;
  903.     }
  904. }
  905.  
  906. /**
  907.  * Provides descriptions for each new function to StarCalc
  908.  * which are shown is the autopilot
  909.  *
  910.  * @param *nNo Input Parameter, Function number between 0 and nCount - 1
  911.  * @param *nParam Parameter Number
  912.  * @param *pName Output: Name of the parameter
  913.  * @param *pDesc Output: Description of the parameter
  914.  *
  915.  * @see #GetFunctionCount, #GetParameterDescription
  916.  */
  917. void CALLTYPE GetParameterDescription( USHORT* nNo, USHORT* nParam,
  918. char* pName, char* pDesc )
  919. {
  920.     *pName = 0;
  921.     *pDesc = 0;
  922.  
  923.     switch ( *nNo ) {
  924.     case 0:    /* Weeks */
  925.         switch ( *nParam ) {
  926.         case 0:
  927.             SO_StringCopy(pDesc,getText(DFA_WEEK_DESC));
  928.             break;
  929.         case 1:
  930.             SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
  931.             SO_StringCopy(pDesc,getText(DFA_WEEK_PAR1_DESC));
  932.             break;
  933.         case 2:
  934.             SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
  935.             SO_StringCopy(pDesc,getText(DFA_WEEK_PAR2_DESC));
  936.             break;
  937.         case 3:
  938.             SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
  939.             SO_StringCopy(pDesc,getText(DFA_WEEK_PAR3_DESC));
  940.             break;
  941.         }
  942.         break;
  943.     case 1: /* Months */
  944.         switch ( *nParam ) {
  945.         case 0:
  946.             SO_StringCopy(pDesc,getText(DFA_MONTHS_DESC));
  947.             break;
  948.         case 1:
  949.             SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
  950.             SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR1_DESC));
  951.             break;
  952.         case 2:
  953.             SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
  954.             SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR2_DESC));
  955.             break;
  956.         case 3:
  957.             SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
  958.             SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR3_DESC));
  959.             break;
  960.         }
  961.         break;
  962.     case 2: /* Years */
  963.         switch ( *nParam ) {
  964.         case 0:
  965.             SO_StringCopy(pDesc,getText(DFA_YEARS_DESC));
  966.             break;
  967.         case 1:
  968.             SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
  969.             SO_StringCopy(pDesc,getText(DFA_YEARS_PAR1_DESC));
  970.             break;
  971.         case 2:
  972.             SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
  973.             SO_StringCopy(pDesc,getText(DFA_YEARS_PAR2_DESC));
  974.             break;
  975.         case 3:
  976.             SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
  977.             SO_StringCopy(pDesc,getText(DFA_YEARS_PAR3_DESC));
  978.             break;
  979.         }
  980.        break;
  981.     case 3:    /* IsLeapYear */
  982.         switch ( *nParam ) {
  983.         case 0:
  984.             SO_StringCopy(pDesc,getText(DFA_ISLEAPYEAR_DESC));
  985.             break;
  986.         case 1:
  987.             SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
  988.             SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
  989.             break;
  990.         }
  991.         break;
  992.     case 4:    /* DaysInMonth */
  993.         switch ( *nParam ) {
  994.         case 0:
  995.             SO_StringCopy(pDesc,getText(DFA_DAYSINMONTH_DESC));
  996.             break;
  997.         case 1:
  998.             SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
  999.             SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
  1000.             break;
  1001.         }
  1002.         break;
  1003.     case 5:    /* DaysInYear */
  1004.         switch ( *nParam ) {
  1005.         case 0:
  1006.             SO_StringCopy(pDesc,getText(DFA_DAYSINYEAR_DESC));
  1007.             break;
  1008.         case 1:
  1009.             SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
  1010.             SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
  1011.             break;
  1012.         }
  1013.         break;
  1014.  
  1015.     case 6:    /* WeeksInYear */
  1016.         switch ( *nParam ) {
  1017.         case 0:
  1018.             SO_StringCopy(pDesc,getText(DFA_WEEKSINYEAR_DESC));
  1019.             break;
  1020.         case 1:
  1021.             SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
  1022.             SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
  1023.             break;
  1024.         }
  1025.         break;
  1026.     }
  1027.  
  1028. }
  1029.  
  1030.  
  1031.  
  1032.