/* toltime.cpp - GNU/tolTcl Library Copyright (C) 2001, 2002, 2003 - Bayes Decisión, SL (Spain [EU]) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if defined(_MSC_VER) #include #endif #include #include #include struct TMS_ClientData { /* timeset iterated */ BUserTimeSet * uts; BDate current; /* token used to remove the command */ Tcl_Command cmd_token; void Init( BUserTimeSet * t) { if ( (uts = t) ) { uts->IncNRefs(); Start( BDate::DefaultFirst() ); } } void Destroy() { if ( uts ) { uts->DecNRefs(); /* destroy in case NRefs has reached 0 */ DESTROY(uts); uts = NULL; } } void Start ( BDate & d ) { if ( uts ) current = uts->FirstNoLess( d ); } void Start ( char * txt ) { if ( txt ) current.PutDate( txt ); else current = BDate::DefaultFirst(); if ( uts ) current = uts->FirstNoLess( current ); } BDate & Get () { return current; } BDate & Next () { if ( uts ) current = uts->Successor( current ); return current; } BDate & Previous () { if ( uts ) current = uts->Predecessor( current ); //current -= uts; return current; } int HasValue () { return current.HasValue(); } int Year() const { return current.Year(); } int Month() const { return current.Month(); } int Day() const { return current.Day(); } int Hour() const { return current.Hour(); } int Minute() const { return current.Minute(); } double Second() const { return current.Second(); } int Contain( BDate & d ) { return uts->Contain( d ); } }; static int Tol_TMSInstanceProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void Tol_TMSDelInstanceProc _ANSI_ARGS_((ClientData clientData)); /* * Create a new command to access the given TOL timeset object name. * */ int Tol_CreateTMSCmd( Tcl_Interp * interp, Tcl_Obj * tmscmd, Tcl_Obj * tmsname, Tcl_Obj * obj_result ) { const BSyntaxObject * tol_obj; BUserTimeSet * uts; Tcl_CmdInfo cmd_info; char * str_tmscmd = Tcl_GetString(tmscmd); if (!*str_tmscmd) { Tcl_AppendStringsToObj(obj_result, "invalid timeset command name: must be not empty", NULL); return TCL_ERROR; } /* verify if tmscmd already exists as a command */ if (Tcl_GetCommandInfo(interp,str_tmscmd,&cmd_info) && (cmd_info.objProc == Tol_TMSInstanceProc)) { Tcl_AppendStringsToObj(obj_result, "\"",str_tmscmd,"\"", "already exists as timeset command",NULL); return TCL_ERROR; } /* now look for tms in tol */ BGrammar * gra = GraTimeSet(); if ( !gra ) { Tcl_AppendStringsToObj( obj_result, "TimeSet grammar not found", NULL ); return TCL_ERROR; } if (!(tol_obj=Tol_ResolveObject(interp, tmsname, obj_result/*, gra*/))) { return TCL_ERROR; } uts = (BUserTimeSet *)tol_obj; TMS_ClientData *clientData = (TMS_ClientData*)Tcl_Alloc(sizeof(TMS_ClientData)); if (!clientData) return TCL_ERROR; clientData->Init(uts); clientData->cmd_token = Tcl_CreateObjCommand( interp, str_tmscmd, &Tol_TMSInstanceProc, (ClientData)clientData, &Tol_TMSDelInstanceProc ); return TCL_OK; } /* * Destroy the tcl tms commands given in objv. * */ int Tol_DestroyTMSCmd( Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[], Tcl_Obj * obj_result ) { Tcl_CmdInfo cmd_info; char * cmdname; for (int i=0; i 3 ) { Tcl_AppendResult( interp, "wrong # args: should be\n", cmd_name, " contain date\n", cmd_name, " start date\n", cmd_name, " get\n", cmd_name, " next\n", cmd_name, " previous", NULL ); return TCL_ERROR; } char * option = Tcl_GetString( objv[1] ); int len = strlen( option ); TMS_ClientData * tmsData = (TMS_ClientData *)clientData; int tcl_code = TCL_OK; BDate dte; if ( !strncmp( "contain", option, len ) ) { if ( objc != 3 ) { Tcl_AppendResult( interp, "wrong # args: should be, ", cmd_name, " contain date", NULL ); tcl_code = TCL_ERROR; } else { tcl_code = Tol_ListToDate( interp, objv[2], dte, Tcl_GetObjResult(interp) ); if ( tcl_code == TCL_OK ) Tcl_SetIntObj( Tcl_GetObjResult(interp), tmsData->Contain( dte ) ); } return tcl_code; } else if ( !strncmp( "start", option, len ) ) { if ( objc != 3 ) { Tcl_AppendResult( interp, "wrong # args: should be, ", cmd_name, " start date", NULL ); tcl_code = TCL_ERROR; } else { tcl_code = Tol_ListToDate( interp, objv[2], dte, Tcl_GetObjResult(interp) ); if ( tcl_code == TCL_OK ) tmsData->Start( dte ); } } else { if ( objc != 2 ) { Tcl_AppendResult( interp, "wrong # args: should be, ", cmd_name, " get\n", cmd_name, " next\n", cmd_name, " previous", NULL ); tcl_code = TCL_ERROR; } else if ( !strncmp( "next", option, len ) ) { tmsData->Next(); } else if ( !strncmp( "previous", option, len ) ) { tmsData->Previous(); } else if ( strncmp( "get", option, len ) ) { Tcl_AppendResult( interp, "invalid option '", option, "', should be: start, get, next or previous", NULL ); tcl_code = TCL_ERROR; } } if ( tcl_code != TCL_ERROR ) { if ( tmsData->HasValue() ) tcl_code = Tol_DateToList( tmsData->Get(), Tcl_GetObjResult(interp) ); else Tcl_SetResult( interp, "-1 -1 -1 -1 -1 -1", TCL_VOLATILE ); } return tcl_code; } void Tol_TMSDelInstanceProc( ClientData clientData ) { TMS_ClientData * tmsData = (TMS_ClientData*)clientData; if ( tmsData ) tmsData->Destroy(); } /* * Implement tol::date * * tol::date first -> default first date * tol::date last -> default last date * tol::date now ?fmt? -> today date/time * tol::date weekday date -> 0(sunday), 1(monday), ..., 6(saturday) * tol::date nod year month -> number of days of month/year * tol::date +day date ?n? -> date ++ ?n days? * tol::date +month date ?n? -> date ++ ?n months? * * Results: * a valid date * * date is always a list {Y M D h m s} * */ int Tol_DateOption( Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[], Tcl_Obj * obj_result ) { char * cmd = Tcl_GetString( objv[0] ); if ( objc < 2 || objc > 4 ) { Tcl_AppendStringsToObj( obj_result, "wrong # args, should be:\n", cmd, " first\n", cmd, " last\n", cmd, " now ?fmt?\n", cmd, " weekday date\n", cmd, " days year month\n", cmd, " +day date ?n?\n", cmd, " +month date ?n?\n", NULL ); return TCL_ERROR; } char * option = Tcl_GetString( objv[1] ); int len = strlen( option ); int tcl_code = TCL_OK; int opt_code; int min_args; int max_args; #define OPT_UNKNOWN -1 #define OPT_FIRST 0 #define OPT_LAST 1 #define OPT_NOW 2 #define OPT_WEEKDAY 3 #define OPT_DAYS 4 #define OPT_INCDAYS 5 #define OPT_INCMONTHS 6 objc -= 2; objv += 2; opt_code = OPT_UNKNOWN; min_args = 0; max_args = 0; if ( !strncmp( "first", option, len ) ) opt_code = OPT_FIRST; else if ( !strncmp( "last", option, len ) ) opt_code = OPT_LAST; else if ( !strncmp( "now", option, len ) ) { opt_code = OPT_NOW; min_args = 0; max_args = 1; } else if ( !strncmp( "weekday", option, len ) ) { opt_code = OPT_WEEKDAY; min_args = max_args = 1; } else if ( !strncmp( "days", option, len ) ) { opt_code = OPT_DAYS; min_args = max_args = 2; } else if ( !strncmp( "+day", option, len ) ) { opt_code = OPT_INCDAYS; min_args = 1; max_args = 2; } else if ( !strncmp( "+month", option, len ) ) { opt_code = OPT_INCMONTHS; min_args = 1; max_args = 2; } else { Tcl_AppendStringsToObj( obj_result, "invalid option, should be: first, last, now, weekday, days, +day or +month", NULL ); return TCL_ERROR; } if ( objc < min_args || objc > max_args ) { Tcl_AppendStringsToObj( obj_result, "wrong # args calling '", cmd, " ", option, "'", NULL ); return TCL_ERROR; } BDate date; int YM[2], i; switch ( opt_code ) { case OPT_FIRST: date = BDate::DefaultFirst(); break; case OPT_LAST: date = BDate::DefaultLast(); break; case OPT_NOW: date = DteNow(); if (objc == 1) { char * fmt = Tcl_GetString( objv[0] ); if ( *fmt ) { BDateFormat bformat( fmt ); BText dfmt( bformat.DateToText(date) ); Tcl_AppendStringsToObj( obj_result, dfmt.Buffer(), NULL ); return TCL_OK; } } break; case OPT_WEEKDAY: tcl_code = Tol_ListToDate( interp, objv[0], date, obj_result ); if ( tcl_code != TCL_OK ) return TCL_ERROR; Tcl_SetIntObj( obj_result, date.WeekDay() % 7 ); return TCL_OK; case OPT_DAYS: for ( i = 0; i < 2; i++ ) { tcl_code = Tcl_GetIntFromObj( interp, objv[i], YM+i ); if ( tcl_code != TCL_OK ) { Tcl_AppendObjToObj( obj_result, Tcl_GetObjResult(interp) ); return TCL_ERROR; } } date.PutDate( YM[0], YM[1] ); if ( !date.HasValue() ) { Tcl_AppendStringsToObj( obj_result, "Invalid month '", Tcl_GetString(objv[0]), "-", Tcl_GetString(objv[1]), "'", NULL ); return TCL_ERROR; } Tcl_SetIntObj( obj_result, DteDaysInMonth( YM[1], YM[0] ) ); return TCL_OK; case OPT_INCDAYS: tcl_code = Tol_ListToDate( interp, objv[0], date, obj_result ); if ( tcl_code != TCL_OK ) return TCL_ERROR; i = 1; if ( objc == 2 ) { tcl_code = Tcl_GetIntFromObj( interp, objv[1], &i ); if ( tcl_code != TCL_OK ) { Tcl_AppendObjToObj( obj_result, Tcl_GetObjResult(interp) ); return TCL_ERROR; } } date.IncDay( i ); break; case OPT_INCMONTHS: tcl_code = Tol_ListToDate( interp, objv[0], date, obj_result ); if ( tcl_code != TCL_OK ) return TCL_ERROR; i = 1; if ( objc == 2 ) { tcl_code = Tcl_GetIntFromObj( interp, objv[1], &i ); if ( tcl_code != TCL_OK ) { Tcl_AppendObjToObj( obj_result, Tcl_GetObjResult(interp) ); return TCL_ERROR; } } date.IncMonth( i ); } return Tol_DateToList(date, obj_result ); } int Tol_ListToDate( Tcl_Interp * interp, Tcl_Obj * list, BDate & date, Tcl_Obj * obj_result ) { int tcl_code; int lst_len; Tcl_Obj ** lst_items; tcl_code = Tcl_ListObjGetElements(interp,list,&lst_len,&lst_items); if (tcl_code != TCL_OK) { Tcl_AppendObjToObj(obj_result,Tcl_GetObjResult(interp)); return TCL_ERROR; } if ( lst_len < 1 || lst_len > 6 ) { Tcl_AppendStringsToObj( obj_result, "Invalid date '", Tcl_GetString(list), "' should be a list {Y ?M D h m s?}", NULL ); return TCL_ERROR; } else { int arr_date[6] = {0,1,1,0,0}; double second = 0.0; int top_int; if ( lst_len < 6 ) top_int = lst_len; else { top_int = 5; tcl_code = Tcl_GetDoubleFromObj( interp, lst_items[5], &second) ; if ( tcl_code != TCL_OK ) { Tcl_AppendObjToObj( obj_result, Tcl_GetObjResult(interp) ); return TCL_ERROR; } } for ( int i = 0; i < top_int; i++ ) { tcl_code = Tcl_GetIntFromObj( interp, lst_items[i], arr_date+i) ; if ( tcl_code != TCL_OK ) { Tcl_AppendObjToObj( obj_result, Tcl_GetObjResult(interp) ); return TCL_ERROR; } } date.PutDate( arr_date[0], arr_date[1], arr_date[2], arr_date[3], arr_date[4], second ); } if ( !date.HasValue() ) { Tcl_AppendStringsToObj( obj_result, "Invalid date '", Tcl_GetString(list), "'", NULL ); return TCL_ERROR; } return TCL_OK; } #define IT_YEAR 0 #define IT_MONTH 1 #define IT_DAY 2 #define IT_HOUR 3 #define IT_MINUTE 4 #define IT_SECOND 5 #define IT_SIZE 6 int Tol_DateToList( BDate & date, Tcl_Obj * obj_result ) { Tcl_Obj * date_items[IT_SIZE]; date_items[IT_YEAR] = Tcl_NewIntObj ( date.Year() ); date_items[IT_MONTH] = Tcl_NewIntObj ( date.Month() ); date_items[IT_DAY] = Tcl_NewIntObj ( date.Day() ); date_items[IT_HOUR] = Tcl_NewIntObj ( date.Hour() ); date_items[IT_MINUTE] = Tcl_NewIntObj ( date.Minute() ); date_items[IT_SECOND] = Tcl_NewDoubleObj( date.Second() ); Tcl_SetListObj( obj_result, IT_SIZE, date_items ); return TCL_OK; }