// // Copyright (C) 2005, Walter Garrote, // 2002, Ferran Pegueroles, // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation; either version 2.1, // or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; see the file COPYING.LIB. If // not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Cobol Compiler Run Time Library -- Intrinsic functions // // #include "htcoblib.h" #include "rterrors.h" #include #ifdef __MINGW32__ #include #endif extern int bDecimalComma; extern char cCurrencySymbol; #define NOT_IMPLEMENTED(x) tcob_rt_error(x,TCERR_NOT_IMPLEMENTED) #define decimal_char() (bDecimalComma?',':'.') #define MAX_ARG_NUMBER 100 unsigned int integer_of_date(unsigned int date); // // // Format for the intrinsic functions : // // MOVE FUNCTION ( [,,...]) TO . // or // MOVE FUNCTION TO . // // void tcob_intrinsic_( struct fld_desc *dest_desc, char *dest_data,...) // [ struct fld_desc *arg_desc, char *arg_data,... ] // // // All the functions accept a variable number of arguments, but only use the asguments // they need. // The first 2 arguments are the only required anr are the destination field. // The caller must push a NULL after last argument, so functions can // now how many arguments are passed. // // // // Util function to convert any numeric field to an integer (similar to tcob_fldtod) // void fldtoint(struct fld_desc *desc, char *data,int *res){ int *num; char pic[5]; struct fld_desc int_desc = { 4, //len DTYPE_BININT, //type 0, // decimals 0, //pscale 0,0,0,0,0,0, //flags NULL //PIC }; tcob_picCreate(pic,5,'S',1,'9',9,NULL); int_desc.pic=pic; if (desc->type == DTYPE_BININT) { num = (int *)data; *res=*num; return ; } tcob_move(desc,data,&int_desc,(char *)res); } //{"ABS",ITYPE_FLOAT,1}, void tcob_intrinsic_abs(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("ABS",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,fabs(num)); } //{"ACOS",ITYPE_FLOAT,1}, void tcob_intrinsic_acos(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("ACOS",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,cos(num)); } //{"ANNUITY",ITYPE_FLOAT,2}, void tcob_intrinsic_annuity(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm1_desc,*parm2_desc; char *parm1_data,*parm2_data; double num1,num2,res; va_start(ap,dest_data); parm1_desc = va_arg(ap,struct fld_desc *); parm1_data = va_arg(ap,char *); parm2_desc = va_arg(ap,struct fld_desc *); parm2_data = va_arg(ap,char *); va_end(ap); if ((parm1_desc == NULL) || (parm1_data == NULL) || (parm2_desc == NULL) || (parm2_data == NULL)) { tcob_rt_error("ANNUITY",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm1_desc,parm1_data,&num1); tcob_fldtod(parm2_desc,parm2_data,&num2); if (num1 == 0) { res = 1/num2; }else{ res = (num1 / (1 - pow((1 - num1),-num2))); } tcob_dtofld(dest_desc,dest_data,0,res); } //{"ASIN",ITYPE_FLOAT,1}, void tcob_intrinsic_asin(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("ASIN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,asin(num)); } //{"ATAN",ITYPE_FLOAT,1}, void tcob_intrinsic_atan(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("ATAN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,atan(num)); } //{"CHAR",ITYPE_ALPHA,1}, // inline //{"COS",ITYPE_FLOAT,1}, void tcob_intrinsic_cos(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("COS",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,cos(num)); } //{"CURRENT-DATE",ITYPE_DATETIME,0}, void tcob_intrinsic_current_date(struct fld_desc *dest_desc, char *dest_data, ...) { time_t now; char now_str[22]; now = time(NULL); // Needs fix to full positions 15 to 21 (miliseconds and dif between local and Univeral Time) strftime(now_str,22,"%Y%m%d%H%M%S0000000",localtime(&now)); memmove(dest_data,now_str,dest_desc->len); } // return the month and date of giving days in year unsigned int mmdd(int yy, int days) { int dd, mm; if(days == 0) return(1231); mm = 0; dd = days; do { dd = days; mm++; switch(mm) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days -= 31; break; case 2: days -= 28; if(((yy % 4) ==0 && (yy % 100) !=0) || (yy % 400) == 0) days--; break; case 4: case 6: case 9: case 11: days -= 30; break; } } while(days > 0); return((mm * 100) + dd); } //{"DATE-OF-INTEGER",ITYPE_DATE,1}, void tcob_intrinsic_date_of_integer(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data, date_str[9]; int days; struct tm date_tm; time_t time; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("DATE-OF-INTEGER",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&days); // walter int yy, r1, r2, r3, r4, dayt; unsigned int aux; days += 584388; r1 = days % 146097; r2 = r1 % 36524; r3 = r2 % 1461; r4 = r3 % 365; yy = ((days / 146097) * 400) + ((r1 / 36524 )* 100) + ((r2 / 1461) * 4) + (r3 / 365) + 1; memset(date_str, 9, 0); if(r4 == 0) // last day, subtract 1 from year yy--; if(r4 == 1 && r3 == 1) { // first day, force to January 1 sprintf(date_str,"%8i",(yy * 10000) + 101); } else { if(r4 == 0) { // whats the last day ? aux = (yy * 10000) + 1231; dayt = integer_of_date(aux) + 584388; if(dayt == days || r1 == 0) sprintf(date_str,"%8i",(yy * 10000) + 1231); else sprintf(date_str,"%8i",(yy * 10000) + 1230); } else sprintf(date_str,"%8i",(yy * 10000) + mmdd(yy, r4)); } memmove(dest_data,date_str,dest_desc->len); return; // // Set the origin of time according to cobol standard // 31 Dec 1600 date_tm.tm_sec=0; /* seconds */ date_tm.tm_min=0; /* minutes */ date_tm.tm_hour=0; /* hours */ date_tm.tm_mday=31; /* day of the month */ date_tm.tm_mon=11; /* month 0 - 11 */ //date_tm.tm_year= -300; /* year */ /* the year 1600 */ // -300 and 0 doesn't work, and by nou we use 1901 instead // of 1600, needs fix date_tm.tm_year=1; /* year */ date_tm.tm_wday=0; /* day of the week */ date_tm.tm_yday=0; /* day in the year */ date_tm.tm_isdst=0; /* daylight saving time */ // Add the number of days indicated date_tm.tm_mday += days; time = mktime(&date_tm); strftime(date_str,9,"%Y%m%d",localtime(&time)); memmove(dest_data,date_str,dest_desc->len); } //{"DATE-TO-YYYYMMDD",ITYPE_DATE,1}, /* Needs to get and use an optinal 3rd argument (described on 2002 standard) */ void tcob_intrinsic_date_to_yyyymmdd(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm1_desc,*parm2_desc; char *parm1_data, *parm2_data; double date,limit=500000; va_start(ap,dest_data); parm1_desc = va_arg(ap,struct fld_desc *); parm1_data = va_arg(ap,char *); parm2_desc = va_arg(ap,struct fld_desc *); parm2_data = va_arg(ap,char *); va_end(ap); if ((parm1_desc == NULL) || (parm1_data == NULL)) { tcob_rt_error("DATE-TO-YYYYMMDD",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm1_desc,parm1_data,&date); if ((parm2_desc != NULL) && (parm2_data != NULL)) { tcob_fldtod(parm2_desc,parm2_data,&limit); limit *= 10000; } if (date > limit) date += 20000000; else date += 19000000; tcob_dtofld(dest_desc,dest_data,0,date); } //{"DAY-OF-INTEGER",ITYPE_JULIANDATE,1}, void tcob_intrinsic_day_of_integer(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data, day_str[8]; int days; struct tm date_tm; time_t time; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("DAY-OF-INTEGER",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&days); // Set the origin of time according to cobol standard // 31 Dec 1600 date_tm.tm_sec=0; /* seconds */ date_tm.tm_min=0; /* minutes */ date_tm.tm_hour=0; /* hours */ date_tm.tm_mday=31; /* day of the month */ date_tm.tm_mon=11; /* month 0 - 11 */ //date_tm.tm_year= -300; /* year */ /* the year 1600 */ // -300 and 0 doesn't work, and by nou we use 1901 instead // of 1600, needs fix date_tm.tm_year=1; /* year */ date_tm.tm_wday=0; /* day of the week */ date_tm.tm_yday=0; /* day in the year */ date_tm.tm_isdst=0; /* daylight saving time */ // Add the number of days indicated date_tm.tm_mday += days; time = mktime(&date_tm); strftime(day_str,8,"%Y%j",localtime(&time)); memmove(dest_data,day_str,dest_desc->len); } //{"DAY-TO-YYYYDDD",ITYPE_JULIANDATE,1}, /* Needs to get and use an optinal 3rd argument (described on 2002 standard) */ void tcob_intrinsic_day_to_yyyyddd(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm1_desc,*parm2_desc; char *parm1_data, *parm2_data; double date,limit=50000; va_start(ap,dest_data); parm1_desc = va_arg(ap,struct fld_desc *); parm1_data = va_arg(ap,char *); parm2_desc = va_arg(ap,struct fld_desc *); parm2_data = va_arg(ap,char *); va_end(ap); if ((parm1_desc == NULL) || (parm1_data == NULL)) { tcob_rt_error("DAY-TO-YYYYDDD",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm1_desc,parm1_data,&date); if ((parm2_desc != NULL) && (parm2_data != NULL)) { tcob_fldtod(parm2_desc,parm2_data,&limit); limit *= 1000; } if (date > limit) date += 2000000; else date += 1900000; tcob_dtofld(dest_desc,dest_data,0,date); } //{"FACTORIAL",ITYPE_INT,1}, static int fact(int num) { if (num < 2) return 1; else return ( fact(num - 1) * num ); } void tcob_intrinsic_factorial(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int num,*dest; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("FACTORIAL",TCERR_INTRINSIC_BAD_ARG); } dest = (int *)dest_data; fldtoint(parm_desc,parm_data,&num); *dest = fact(num); } //{"INTEGER",ITYPE_INT,1}, void tcob_intrinsic_integer(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int num,*dest; double parm; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("INTEGER",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&parm); fldtoint(parm_desc,parm_data,&num); // greatest Integer not greater than parm if (num > parm) num = num - 1; dest= (int *)dest_data; *dest=num; } // return the days in giving year unsigned int days_in_year(unsigned int date) { int days_in_year, yy, mm, dd; yy = (date / 10000); mm = (date - (yy * 10000)) / 100; dd = date % 100; days_in_year = 0; while(--mm) { switch(mm) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days_in_year += 31; break; case 2: days_in_year += 28; if(((yy % 4) ==0 && (yy % 100) !=0) || (yy % 400) == 0) days_in_year++; break; case 4: case 6: case 9: case 11: days_in_year += 30; break; } } days_in_year += dd; return(days_in_year); } // return the number of days after 16010101 unsigned int integer_of_date(unsigned int date) { int year, cc, yy; unsigned int days; year = date / 10000; cc = year / 100; yy = year % 100; days = days_in_year(date) + ((year - 1) * 365) + (cc * 24) + (cc / 4) + ((yy - 1) / 4) - 584388; return(days); } //{"INTEGER-OF-DATE",ITYPE_INT,1}, void tcob_intrinsic_integer_of_date(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; struct tm date_tm,orig; int date,day,month,year,*dest; double secs; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("INTEGER-OF-DATE",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&date); // date : yyyymmdd // walter dest=(int *)dest_data; *dest = integer_of_date(date); return; // day=date % 100; month=(date / 100) % 100; year=date / 10000; // Set the origin of time according to cobol standard // 31 Dec 1600 orig.tm_sec=0; /* seconds */ orig.tm_min=0; /* minutes */ orig.tm_hour=0; /* hours */ orig.tm_mday=31; /* day of the month */ orig.tm_mon=11; /* month 0 - 11 */ //date_tm.tm_year= -300; /* year */ /* the year 1600 */ // -300 and 0 doesn't work, and by nou we use 1901 instead // of 1600, needs fix orig.tm_year=1; /* year 0 = 1900*/ orig.tm_wday=0; /* day of the week */ orig.tm_yday=0; /* day in the year */ orig.tm_isdst=0; /* daylight saving time */ date_tm.tm_sec=0; /* seconds */ date_tm.tm_min=0; /* minutes */ date_tm.tm_hour=0; /* hours */ date_tm.tm_mday=day; /* day of the month */ date_tm.tm_mon=month - 1; /* month 0 - 11 */ date_tm.tm_year=year - 1900; /* year 0 = 1900*/ date_tm.tm_wday=0; /* day of the week */ date_tm.tm_yday=0; /* day in the year */ date_tm.tm_isdst=0; /* daylight saving time */ // Add the number of days indicated secs = difftime(mktime(&date_tm),mktime(&orig)); dest=(int *)dest_data; *dest=(int) (secs / (60 * 60 * 24)) + 1; } //{"INTEGER-OF-DAY",ITYPE_INT,1}, void tcob_intrinsic_integer_of_day(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; struct tm date_tm,orig; int date,day,year,*dest; double secs; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("INTEGER-OF-DAY",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&date); // date : yyyyddd day=date % 1000; year=date / 1000; // Set the origin of time according to cobol standard // 31 Dec 1600 orig.tm_sec=0; /* seconds */ orig.tm_min=0; /* minutes */ orig.tm_hour=0; /* hours */ orig.tm_mday=31; /* day of the month */ orig.tm_mon=11; /* month 0 - 11 */ //date_tm.tm_year= -300; /* year */ /* the year 1600 */ // -300 and 0 doesn't work, and by nou we use 1901 instead // of 1600, needs fix orig.tm_year=1; /* year 0 = 1900*/ orig.tm_wday=0; /* day of the week */ orig.tm_yday=0; /* day in the year */ orig.tm_isdst=0; /* daylight saving time */ date_tm.tm_sec=0; /* seconds */ date_tm.tm_min=0; /* minutes */ date_tm.tm_hour=0; /* hours */ date_tm.tm_mday=day; /* day of the month */ date_tm.tm_mon=0; /* month 0 - 11 */ date_tm.tm_year=year - 1900; /* year 0 = 1900*/ date_tm.tm_wday=0; /* day of the week */ date_tm.tm_yday=0; /* day in the year */ date_tm.tm_isdst=0; /* daylight saving time */ // Add the number of days indicated //fprintf(stderr,"%s\n",ctime(mktime(&orig))); secs = difftime(mktime(&date_tm),mktime(&orig)); dest=(int *)dest_data; *dest=(int) (secs / (60 * 60 * 24)) + 1; } //{"INTEGER-PART",ITYPE_INT,1}, void tcob_intrinsic_integer_part(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int num,*dest; double parm; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("INTEGER-PART",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&parm); fldtoint(parm_desc,parm_data,&num); // greatest Integer not greater than parm if (num > 0){ if ( num > parm) num--; } else { if ( num < parm) num++; } dest= (int *)dest_data; *dest=num; } //{"LENGTH",ITYPE_INT,1}, // inline //{"LOG",ITYPE_FLOAT,1}, void tcob_intrinsic_log(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("LOG",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,log(num)); } //{"LOG10",ITYPE_FLOAT,1}, void tcob_intrinsic_log10(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("LOG10",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,log10(num)); } //{"LOWER-CASE",ITYPE_ALPHA,1}, void tcob_intrinsic_lower_case(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int i,max_len; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("LOWER-CASE",TCERR_INTRINSIC_BAD_ARG); } if ((parm_desc->type != DTYPE_ALPHANUMERIC) && (parm_desc->type != DTYPE_ALPHA) && (parm_desc->type != DTYPE_GROUP)) { tcob_rt_error("LOWER-CASE",TCERR_INTRINSIC_BAD_ARG); } max_len = tc_min(parm_desc->len,dest_desc->len); for(i=0;i < max_len;i++){ dest_data[i]=tolower(parm_data[i]); } } //{"MAX",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_max(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num,max; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("MAX",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&max); // move the first number to the maximum while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); if (num > max) max=num; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); tcob_dtofld(dest_desc,dest_data,0,max); } //{"MEAN",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_mean(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num,mean; int count; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("MEAN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&mean); // move the first number to the mean count = 1; while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); mean = mean + num; count++; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } mean = mean / count; va_end(ap); tcob_dtofld(dest_desc,dest_data,0,mean); } //{"MEDIAN",ITYPE_FLOAT,ANY_NUMBER}, struct double_list { struct double_list *next; double num; }; void tcob_intrinsic_median(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; struct double_list *list; struct double_list *item; struct double_list *new_item; int count,i; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("MEDIAN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); // move the first number list=tcob_rt_malloc("MEDIAN",sizeof(struct double_list)); list->next = NULL; list->num = num; count = 1; while((parm_desc !=NULL) && (parm_data !=NULL)){ //create an ordered list tcob_fldtod(parm_desc,parm_data,&num); for(item=list;item->next!=NULL;item=item->next) { if (item->num > num){ new_item=tcob_rt_malloc("MEDIAN",sizeof(struct double_list)); new_item->next = item->next; new_item->num = num; item->next = new_item; break; } } count++; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } // find the element in the middle of list for(i=0,item=list;i< count/2;i++,item=item->next) ; num = item->num; va_end(ap); tcob_dtofld(dest_desc,dest_data,0,num); } //{"MIDRANGE",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_midrange(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num,min,max; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("MIDRANGE",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&min); // move the first number to the minimum max = min; // and to the maximum while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); if (num < min) min=num; if (num > max) max=num; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); num = (max - min) / 2; tcob_dtofld(dest_desc,dest_data,0,num); } //{"MIN",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_min(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num,min; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("MIN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&min); // move the first number to the minimum while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); if (num < min) min=num; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); tcob_dtofld(dest_desc,dest_data,0,min); } //{"MOD",ITYPE_INT,2}, void tcob_intrinsic_mod(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int int1,int2; int *mod; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // Argument 1 tcob_rt_error("MOD",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&int1); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // Argument 2 tcob_rt_error("MOD",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&int2); va_end(ap); mod=(int *)dest_data; *mod=int1%int2; } /* * Parses the string and returns the number that the string represents. * Is currency = 1, the string can ccontain currency simbols. * */ static double parse_numval(char *str,int currency){ char *p; char digits[50]; int num_digits=0,sign=0; double num; p=str; while(isspace((int)*p)) p++; if (currency) { if (*p == cCurrencySymbol) { p++; while(isspace((int)*p)) p++; } } if (*p=='+') { sign = +1; p++; } else if (*p=='-') { sign = -1; p++; } while(isspace((int)*p)) p++; while(isdigit((int)*p)){ digits[num_digits]=*p; num_digits++; p++; } if (*p == decimal_char()){ digits[num_digits]='.'; num_digits++; p++; } while(isdigit((int)*p)){ digits[num_digits]=*p; num_digits++; p++; } while(isspace((int)*p)) p++; if (*p=='+') { sign = +1; p++; } else if (*p=='-') { sign = -1; p++; } else if ( strncasecmp(p,"CR",2) == 0) { sign = -1; p+=2; } else if ( strncasecmp(p,"DB",2) == 0) { sign = -1; p+=2; } if (currency) { if (*p == cCurrencySymbol) { p++; while(isspace((int)*p)) p++; } } digits[num_digits]='\0'; num = atof(digits); if (sign < 0) num = num * -1 ; return num; } //{"NUMVAL",ITYPE_FLOAT,1}, void tcob_intrinsic_numval(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; char *str; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // Argument 1 tcob_rt_error("NUMVAL",TCERR_INTRINSIC_BAD_ARG); } va_end(ap); str = tcob_rt_malloc("NUMVAL",parm_desc->len + 1); memmove(str,parm_data,parm_desc->len); str[parm_desc->len]='\0'; num = parse_numval(str,0); free(str); //fprintf(stderr,"str:<%s>digits<%s>n:<%f>\n",str,digits,num); tcob_dtofld(dest_desc,dest_data,0,num); } //{"NUMVAL-C",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_numval_c(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; char *str; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // Argument 1 tcob_rt_error("NUMVAL-C",TCERR_INTRINSIC_BAD_ARG); } va_end(ap); str = tcob_rt_malloc("NUMVAL-C",parm_desc->len + 1); if (str == NULL ){ //report error } memmove(str,parm_data,parm_desc->len); str[parm_desc->len]='\0'; num = parse_numval(str,1); free(str); //fprintf(stderr,"str:<%s>digits<%s>n:<%f>\n",str,digits,num); tcob_dtofld(dest_desc,dest_data,0,num); } //{"ORD",ITYPE_INT,1}, // inline //{"ORD-MAX",ITYPE_INT,ANY_NUMBER}, void tcob_intrinsic_ord_max(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num,max; int *ord_max,count; ord_max=(int *)dest_data; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("ORD-MAX",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&max); // move the first number to the maximum count = 1; *ord_max = 1; while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); count++; if (num > max) { max=num; *ord_max=count;} parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); } //{"ORD-MIN",ITYPE_INT,ANY_NUMBER}, void tcob_intrinsic_ord_min(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num,min; int *ord_min,count; ord_min=(int *)dest_data; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("ORD-MIN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&min); // move the first number to the minimum count = 1; *ord_min = 1; while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); count++; if (num < min) { min=num; *ord_min=count;} parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); } //{"PRESENT-VALUE",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_present_value(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double args[MAX_ARG_NUMBER]; double res; int count,i; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas two arguments are required tcob_rt_error("PRESENT-VALUE",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&args[0]); // move the first number parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); count = 1; while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&args[count]); count++; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); if (count < 2) { // At leas two arguments are required tcob_rt_error("PRESENT-VALUE",TCERR_INTRINSIC_BAD_ARG); } for(i = 1;i< count;i++) { res = res + ( args[i] / pow( 1 + args[0],i)); } tcob_dtofld(dest_desc,dest_data,0,res); } //{"RANDOM",ITYPE_FLOAT,1}, void tcob_intrinsic_random(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int seed; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc != NULL) && (parm_data != NULL)) { // If an argument is speciufied is the seed fldtoint(parm_desc,parm_data,&seed); // move the seed srand(seed); } tcob_dtofld(dest_desc,dest_data,0,rand()); } //{"RANGE",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_range(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double min,max,num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("RANGE",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&min); // move the first number to the minimum max = min; // and to the maximum while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&num); if (num < min) min=num; if (num > max) max=num; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); tcob_dtofld(dest_desc,dest_data,0,(max - min)); } //{"REM",ITYPE_INT,2}, void tcob_intrinsic_rem(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int int1,int2;//,div; int *res; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // 2 arguments required tcob_rt_error("REM",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&int1); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // 2 arguments required tcob_rt_error("REM",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&int2); va_end(ap); res=(int *)dest_data; // walter *res = int1 % int2; // div = int1 / int2; // *res=int1 - int2*div; } //{"REVERSE",ITYPE_ALPHA,1}, void tcob_intrinsic_reverse(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int i,max_len; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("REVERSE",TCERR_INTRINSIC_BAD_ARG); } if ((parm_desc->type != DTYPE_ALPHANUMERIC) && (parm_desc->type != DTYPE_ALPHA) && (parm_desc->type != DTYPE_GROUP)) { tcob_rt_error("REVERSE",TCERR_INTRINSIC_BAD_ARG); } max_len = tc_min(parm_desc->len,dest_desc->len); for(i=0;i < max_len;i++){ dest_data[i]=parm_data[parm_desc->len - i]; } } //{"SIN",ITYPE_FLOAT,1}, void tcob_intrinsic_sin(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("SIN",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,sin(num)); } //{"SQRT",ITYPE_FLOAT,1}, void tcob_intrinsic_sqrt(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double num; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("SQRT",TCERR_INTRINSIC_BAD_ARG); } tcob_fldtod(parm_desc,parm_data,&num); tcob_dtofld(dest_desc,dest_data,0,sqrt(num)); } //{"STANDARD-DEVIATION",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_standard_deviation(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double args[MAX_ARG_NUMBER]; double mean; double res; int i,count; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("STANDARD-DEVIATION",TCERR_INTRINSIC_BAD_ARG); } count=1; tcob_fldtod(parm_desc,parm_data,&args[0]); // move the first number while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&args[count]); count ++; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); // calculate the mean; mean=0; for(i=0;i 9999)){ *res=1; return; } if ((month < 1) || (month > 12)){ *res=1; return; } switch(month){ case 2: if (day > 29) { *res=1; return; } break; case 4: case 6: case 9: case 11: if (day > 29) { *res=1; return; } break; default: if (day > 31) { *res=1; return; } break; } *res=0; } //{"TEST-DAY-YYYYDDD",ITYPE_INT,1}, void tcob_intrinsic_test_day_yyyyddd(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int *res; int date,day,year; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("TEST-DAY-YYYYDDD",TCERR_INTRINSIC_BAD_ARG); } fldtoint(parm_desc,parm_data,&date); day=date % 1000; year=date / 1000; res=(int *)dest_data; if ((year < 1600) || (year > 9999)){ *res=1; return; } if ((day < 1) || (day > 366)){ *res=1; return; } *res=0; } //{"UPPER-CASE",ITYPE_ALPHA,1}, void tcob_intrinsic_upper_case(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; int i,max_len; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); va_end(ap); if ((parm_desc == NULL) || (parm_data == NULL)) { tcob_rt_error("UPPER-CASE",TCERR_INTRINSIC_BAD_ARG); } if ((parm_desc->type != DTYPE_ALPHANUMERIC) && (parm_desc->type != DTYPE_ALPHA) && (parm_desc->type != DTYPE_GROUP)) { tcob_rt_error("UPPER-CASE",TCERR_INTRINSIC_BAD_ARG); } max_len = tc_min(parm_desc->len,dest_desc->len); for(i=0;i < max_len;i++){ dest_data[i]=toupper(parm_data[i]); } } //{"VARIANCE",ITYPE_FLOAT,ANY_NUMBER}, void tcob_intrinsic_variance(struct fld_desc *dest_desc, char *dest_data, ...) { va_list ap; struct fld_desc *parm_desc; char *parm_data; double args[MAX_ARG_NUMBER]; double mean; double res; int i,count; va_start(ap,dest_data); parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); if ((parm_desc == NULL) || (parm_data == NULL)) { // At leas one argumetn is required tcob_rt_error("VARIANCE",TCERR_INTRINSIC_BAD_ARG); } count=1; tcob_fldtod(parm_desc,parm_data,&args[0]); // move the first number while((parm_desc !=NULL) && (parm_data !=NULL)){ tcob_fldtod(parm_desc,parm_data,&args[count]); count ++; parm_desc = va_arg(ap,struct fld_desc *); parm_data = va_arg(ap,char *); } va_end(ap); // calculate the mean; mean=0; for(i=0;i limit) { year += 2000; } else { year += 1900; } } tcob_dtofld(dest_desc,dest_data,0,year); }